Added working C & C++ leven_diff(), added `exopt::util::comptime_value()`.

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 − 凶
boxed_is_boxed_value
Avril 1 year ago
parent 388068bc1d
commit b778b47ae8
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -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 */

@ -1,6 +1,8 @@
#ifndef _LEVEN_H
#define _LEVEN_H
#include "exopt.h"
#ifdef __cplusplus
#include <string_view>
@ -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<decltype(a), decltype(b)>
requires(requires(decltype(a) _a, decltype(b) _b) {
{ _a < _b } -> std::convertible_to<bool>;
}) {
return a < b ? a : b;
}*/
/// Compute the levenshtein distance.
constexpr auto leven_diff(std::convertible_to<std::string_view> auto const& a, std::convertible_to<std::string_view> 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<signed long>(! (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<std::vector<signed long>>;
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<Vec2*>(this)); }
constexpr operator Vec2&() const&& = delete;
};
const auto inner = std::vector<signed long>{ size_t(m) + 1 };
std::vector<std::vector<signed long>> d{ static_cast<Vec2&&>(std::move(vec{size_t(n) + 1, inner})) };
return work_on_d(d);
} else {
auto** d = reinterpret_cast<signed long**>(allocate_array(sizeof(signed long), m+1, n+1));
try {
return work_on_d(d);
} catch(...) {
deallocate_array(reinterpret_cast<void**>(d));
throw;
}
}
}
#endif
constexpr auto leven_diff(std::string_view s1, std::string_view s2) noexcept {
const size_t
m(s1.size()),

@ -0,0 +1,36 @@
#pragma once
#include <utility>
#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<typename T, typename U>
concept comptime = std::convertible_to<T, U> 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<U> 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()");
} }

@ -3,6 +3,16 @@
#include <cstring>
#include <leven.h>
#include <util.hh>
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")]] {

Loading…
Cancel
Save