From b778b47ae8bf1576c4aa5aefcd51c6303b6d3df1 Mon Sep 17 00:00:00 2001 From: Avril Date: Sun, 16 Apr 2023 18:20:19 +0100 Subject: [PATCH] Added working C & C++ leven_diff(), added `exopt::util::comptime_value()`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: Add default `util::comptime<>` parameters to constexpr `leven_diff()` for when size of strings are statically known. Fortune for libexopt's current commit: Curse − 凶 --- include/exopt.h | 44 +++++++++++++++++++++++++++ include/leven.h | 79 +++++-------------------------------------------- include/util.hh | 36 ++++++++++++++++++++++ src/leven.cpp | 10 +++++++ 4 files changed, 98 insertions(+), 71 deletions(-) create mode 100644 include/exopt.h create mode 100644 include/util.hh diff --git a/include/exopt.h b/include/exopt.h new file mode 100644 index 0000000..aecc0a6 --- /dev/null +++ b/include/exopt.h @@ -0,0 +1,44 @@ +#ifndef _EXOPT_H +#define _EXOPT_H + +#define _EXOPT_INTERNAL_PREFIX _exopt__ + +#ifdef __cplusplus +# define _exopt__cpp 1 +# define _exopt__c 1 +extern "C" { +#else +# define _exopt__cpp 0 +# define _exopt__c 1 +#endif + +#define _EO_PASTE_(x,y) x##y +#define _EO_PASTE(x,y) _EO_PASTE_(x,y) +#define _EO(X) _EO_PASTE(_EXOPT_INTERNAL_PREFIX, X) + + +#define _exopt__internal __attribute__((visibility("internal"))) +#define _exopt__readonly __attribute__((__pure__)) +#define _exopt__pure __attribute__((__const__)) + +#ifdef _EO__OPT_OLD_ASSUME +# define _EO_ASSUME(X) ({ if(! (X)) __builtin_unreachable(); }) +#endif + +#if _EO(cpp) +# ifndef _EO_ASSUME +# define _EO_ASSUME(X) [[assume(X)]] +# endif +# define _exopt__restrict __restrict__ +#else +# ifndef _EO_ASSUME +# define _EO_ASSUME(X) __attribute__((assume(X))) +# endif +# define _exopt__restrict restrict +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _EXOPT_H */ diff --git a/include/leven.h b/include/leven.h index 0eb26f8..3067af7 100644 --- a/include/leven.h +++ b/include/leven.h @@ -1,6 +1,8 @@ #ifndef _LEVEN_H #define _LEVEN_H +#include "exopt.h" + #ifdef __cplusplus #include @@ -12,81 +14,16 @@ extern "C" { #endif +size_t _EO(leven_diff)(const char* _EO(restrict), const char* _EO(restrict), size_t) + _EO(internal) + _EO(readonly) + __attribute__((nonnull(1, 2))) +; + #ifdef __cplusplus } namespace exopt { namespace util [[gnu::visibility("internal")]] { -#if 0 - void** allocate_array(size_t elem, size_t d1, size_t d2) [[gnu::returns_nonnull]]; - void deallocate_array(void** array) noexcept; - - /*constexpr auto min(auto const& a, auto const& b) noexcept - -> std::common_type_t - requires(requires(decltype(a) _a, decltype(b) _b) { - { _a < _b } -> std::convertible_to; - }) { - return a < b ? a : b; - }*/ - - /// Compute the levenshtein distance. - constexpr auto leven_diff(std::convertible_to auto const& a, std::convertible_to auto const& b) noexcept { - std::string_view s = a, - t = b; - const signed long n = long(s.size()); - const signed long m = long(t.size()); - - if(__builtin_expect(!n, 0)) return m; - if(__builtin_expect(!m, 0)) return n; - - //constexpr - auto&& work_on_d = [&](auto& d) { - for(long i=0; i <= n ; d[i][0] = i) i+=1; - for(long i=0; i <= m ; d[0][i] = i) i+=1; - - for(long i=1; i <= n; i++) { - for(long j=1; j<=m; j++) - { - using std::min; - const auto cost = std::type_identity_t(! (t[j-1] == s[i-1])); - d[i][j] = min( - min(d[i-1][j] + 1, d[i][j-1] + 1) - , d[i-1][j-1] + cost); - } - } - return d[n][m]; - }; - //TODO: XXX Multidimensional array not working... fuck THIS - if consteval { - using Vec2 = std::vector>; - struct vec : public Vec2 ///TODO: XXX: best way to do this? We just want the `d`` ctor overload... - { -//TODO: for below ctor of inner (size_t, constT&), since it's ambiguous and chooses the incorrect one no matter what - using Vec2::Vec2;//(size_t, signed long const&, Vec2::allocator_type const&); - vec(signed long, signed long) = delete; - vec(signed long, size_t) = delete; - vec(size_t) = delete; - - constexpr ~vec() noexcept = default; - - - constexpr operator Vec2&&() && noexcept { return std::move(*static_cast(this)); } - constexpr operator Vec2&() const&& = delete; - }; - - const auto inner = std::vector{ size_t(m) + 1 }; - std::vector> d{ static_cast(std::move(vec{size_t(n) + 1, inner})) }; - return work_on_d(d); - } else { - auto** d = reinterpret_cast(allocate_array(sizeof(signed long), m+1, n+1)); - try { - return work_on_d(d); - } catch(...) { - deallocate_array(reinterpret_cast(d)); - throw; - } - } - } -#endif constexpr auto leven_diff(std::string_view s1, std::string_view s2) noexcept { const size_t m(s1.size()), diff --git a/include/util.hh b/include/util.hh new file mode 100644 index 0000000..762517f --- /dev/null +++ b/include/util.hh @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "exopt.h" + +#define _EO_CONSTANT_VALUE(X) ([] { \ + struct { \ + typedef decltype(X) comptime_constant_t; \ + consteval operator comptime_constant_t() const noexcept { return (X); } \ + } inner; \ + return inner; \ +}()) + +namespace exopt { namespace util [[gnu::visibility("internal")]] { + template + concept comptime = std::convertible_to and requires{ + typename T::comptime_constant_t; + }; + + constexpr auto comptime_value(auto value) noexcept { + using U = decltype(value); + struct inner { + typedef U comptime_constant_t; + consteval operator comptime_constant_t() const noexcept { return std::move(value); } + U value; + + constexpr inner(std::add_rvalue_reference_t m) noexcept : value(std::move(m)) {} + constexpr ~inner() = default; + }; + return inner{ std::move(value) }; + } + + static_assert(comptime_value(std::string_view{"hello"}.size()) == 5, "Bad comptime_value()"); + static_assert(_EO_CONSTANT_VALUE(std::string_view{"hello world"}) == std::string_view{"hello world"}, "Bad CONSTANT_VALUE()"); +} } diff --git a/src/leven.cpp b/src/leven.cpp index 83bd798..6feb917 100644 --- a/src/leven.cpp +++ b/src/leven.cpp @@ -3,6 +3,16 @@ #include #include +#include + +extern "C" { + _EO(internal) + _EO(readonly) + __attribute__((nonnull(1, 2))) + size_t _EO(leven_diff)(const char* _EO(restrict) a, const char* _EO(restrict) b, size_t n) { + return exopt::util::leven_diff(std::string_view{a, n}, std::string_view{b, n}); + } +} namespace exopt { namespace util [[gnu::visibility("internal")]] {