|
|
|
#ifndef _LEVEN_H
|
|
|
|
#define _LEVEN_H
|
|
|
|
|
|
|
|
#include "exopt.h"
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
|
|
|
#include <string_view>
|
|
|
|
#include <concepts>
|
|
|
|
#include <vector>
|
|
|
|
#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")]] {
|
|
|
|
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 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});
|
|
|
|
}
|
|
|
|
|
|
|
|
} }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* _LEVEN_H */
|