#ifndef _LEVEN_H #define _LEVEN_H #include "exopt.h" #ifdef __cplusplus #include #include #include #include #include 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")]] { 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(n + 1)); } else { thread_local static std::vector 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{d.begin(), n1}); } } template S1, std::convertible_to 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}); } } } #endif #endif /* _LEVEN_H */