You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libexopt/include/leven.h

96 lines
2.3 KiB

#ifndef _LEVEN_H
#define _LEVEN_H
#include "exopt.h"
#ifdef __cplusplus
//#include "util.hh"
#include <string_view>
#include <concepts>
#include <vector>
#include <array>
#include <span>
#include <tuple>
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")]] {
template<size_t N =0> // NOTE: Do not change this manually //
constexpr auto leven_diff(std::string_view s1, std::string_view s2) noexcept {
const size_t
m(s1.size()),
n(s2.size());
if(__builtin_expect(!m, false)) return n;
if(__builtin_expect(!n, false)) return m;
auto&& work_on_d = [&](auto&& costs) {
for(size_t i=0;i <= n; i++) costs[i] = i;
size_t i{0};
for(auto const& c1: s1) {
costs[0] = i + 1;
size_t corner { i },
j { 0 };
for(auto const& c2: s2) {
size_t upper { costs[j+1] };
if( c1 == c2 ) costs[j+1] = corner;
else {
using std::min;
size_t t{min(upper, corner)};//upper<corner ? upper : corner
costs[j+1] = min(costs[j], t) + 1;
}
corner = upper;
j += 1;
}
i += 1;
}
return costs[n];
};
if constexpr(N > 0) {
return work_on_d(std::array<size_t, N+1>{});
} else if consteval {
return work_on_d(std::vector<size_t>(n + 1));
} else {
thread_local static std::vector<size_t> d;
const size_t n1 = n + 1;
if(__builtin_expect(d.size() < n1, false)) d.resize(n1);
// We don't need to clear the buffer, it will be reinitialised by `work_on_d()`.
return work_on_d(std::span<size_t>{d.begin(), n1});
}
}
template<std::convertible_to<std::string_view> S1, std::convertible_to<std::string_view> S2>
constexpr decltype(auto) leven_diff(const S1& sa, const S2& sb) noexcept {
using str = std::string_view;
return leven_diff(str{sa}, str{sb});
}
template<size_t M, size_t N>
constexpr decltype(auto) leven_diff(const char (&sa)[M], const char (&sb)[N]) noexcept {
if constexpr(!N) return M;
else if constexpr(!M) return N;
else if constexpr(M < N) return N - M; //XXX: Are these lines correct?
else if constexpr(N < M) return M - N; // ^
else return leven_diff<N>(std::string_view{sa}, std::string_view{sb});
}
} }
#endif
#endif /* _LEVEN_H */