Added `string_ord::make_dynamic()`: Returns an anonymous type derived from `OrderedString`.

Fortune for libexopt's current commit: Middle blessing − 中吉
boxed_is_boxed_value
Avril 2 years ago
parent ea8121058f
commit 807008d965
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -102,12 +102,30 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
else return leven_diff<N>(std::string_view{sa}, std::string_view{sb}); else return leven_diff<N>(std::string_view{sa}, std::string_view{sb});
} }
class OrderedString {
public:
constexpr OrderedString() noexcept = default;
constexpr OrderedString(OrderedString const&) noexcept = default;
constexpr OrderedString(OrderedString &&) noexcept = default;
constexpr OrderedString& operator=(OrderedString const&) noexcept = default;
constexpr OrderedString& operator=(OrderedString &&) noexcept = default;
constexpr virtual ~OrderedString() = default;
constexpr virtual std::string_view view() const noexcept = 0;
constexpr virtual size_t size() const noexcept { return view().size(); }
constexpr operator std::string_view() const noexcept { return view(); }
};
/// String that is ordered by Levenshtein distance. /// String that is ordered by Levenshtein distance.
/// ///
/// Used as sorted map key for finding suggestions for possible typos. All valid strings are added as `string_ord`, and the invalid string lookup looks for its closest neighbour(s), those are presented to the user in a "did you mean ..." format with the lowest distance first and so on. /// Used as sorted map key for finding suggestions for possible typos. All valid strings are added as `string_ord`, and the invalid string lookup looks for its closest neighbour(s), those are presented to the user in a "did you mean ..." format with the lowest distance first and so on.
template<std::convertible_to<std::string_view> S> template<std::convertible_to<std::string_view> S>
struct string_ord { struct string_ord {
using string_type = std::remove_reference_t<S>; using string_type = std::remove_reference_t<S>;
constexpr static inline bool is_array = std::is_array_v<string_type>;
constexpr static size_t array_size() noexcept requires(is_array) { return sizeof(string_type) - 1; }
//constexpr static inline size_t ARRAY_SIZE = array_size();
template<typename... Args> requires(std::is_constructible_v<string_type, Args...>) template<typename... Args> requires(std::is_constructible_v<string_type, Args...>)
constexpr string_ord(Args&&... args) noexcept(std::is_nothrow_constructible_v<string_type, Args...>) constexpr string_ord(Args&&... args) noexcept(std::is_nothrow_constructible_v<string_type, Args...>)
@ -134,13 +152,16 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
constexpr auto difference_to(std::convertible_to<std::string_view> auto const& str) const noexcept { constexpr auto difference_to(std::convertible_to<std::string_view> auto const& str) const noexcept {
return leven_diff(std::forward<decltype(str)>(str), m_string); return leven_diff(std::forward<decltype(str)>(str), m_string);
} }
constexpr friend auto operator<=>(const string_ord& a, const string_ord& b) noexcept {
template<std::convertible_to<std::string_view> S2>
constexpr friend auto operator<=>(const string_ord& a, const string_ord<S2>& b) noexcept {
auto ab = leven_diff(a.m_string, b.m_string); auto ab = leven_diff(a.m_string, b.m_string);
auto ba = leven_diff(b.m_string, a.m_string); auto ba = leven_diff(b.m_string, a.m_string);
return ab <=> ba; return ab <=> ba;
} }
constexpr std::string_view view() const noexcept { if constexpr(std::is_array_v<string_type>) return { m_string, sizeof(string_type) - 1 }; else return { m_string }; } constexpr std::string_view view() const noexcept { if constexpr(std::is_array_v<string_type>) return { m_string, sizeof(string_type) - 1 }; else return { m_string }; }
constexpr size_t size() const noexcept { if constexpr(std::is_array_v<string_type>) return sizeof(string_type) - 1; else return view().size(); }
constexpr operator std::string_view() const noexcept { return view(); } constexpr operator std::string_view() const noexcept { return view(); }
template<typename U> requires(std::is_convertible_v<U, std::string_view> and std::is_convertible_v<string_type&&, U>) template<typename U> requires(std::is_convertible_v<U, std::string_view> and std::is_convertible_v<string_type&&, U>)
@ -161,6 +182,46 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
constexpr string_type&& operator*() && noexcept { return std::move(m_string); } constexpr string_type&& operator*() && noexcept { return std::move(m_string); }
constexpr string_type const&& operator*() const&& noexcept { return std::move(m_string); } constexpr string_type const&& operator*() const&& noexcept { return std::move(m_string); }
constexpr decltype(auto) make_dynamic() const noexcept requires(std::is_copy_constructible_v<string_ord<S>>){
return string_ord<S>{ *this }.make_dynamic();
}
constexpr auto make_dynamic() && noexcept {
if constexpr(std::is_array_v<string_type>) {
struct OS : public OrderedString {
std::array<char, sizeof(string_type)> str;
constexpr virtual ~OS() = default;
constexpr OS(string_type const& str) noexcept : OrderedString(), str(util::array_literal(std::forward<decltype(str)>(str))) {}
constexpr OS(const OS&) = default;
constexpr OS(OS&&) = default;
constexpr OS& operator=(const OS&) = default;
constexpr OS& operator=(OS &&) = default;
constexpr virtual size_t size() const noexcept override { return sizeof(string_type)-1; }
constexpr virtual std::string_view view() const noexcept override { return { str.data(), sizeof(string_type)-1 }; }
};
return OS { std::move(m_string) };
} else {
struct OS : public OrderedString {
string_type str;
constexpr virtual ~OS() = default;
constexpr OS(string_type&& str) noexcept : OrderedString(), str(std::move(str)) {}
constexpr OS(const OS&) = default;
constexpr OS(OS&&) = default;
constexpr virtual std::string_view view() const noexcept override { return { str }; }
constexpr OS& operator=(const OS&) = default;
constexpr OS& operator=(OS &&) = default;
};
return OS { std::move(m_string) };
}
}
private: private:
template<size_t... Is> requires(sizeof...(Is) == sizeof(string_type)) template<size_t... Is> requires(sizeof...(Is) == sizeof(string_type))
constexpr string_ord(const char (&&l)[sizeof(string_type)], std::index_sequence<Is...>) noexcept requires(std::is_array_v<string_type>) constexpr string_ord(const char (&&l)[sizeof(string_type)], std::index_sequence<Is...>) noexcept requires(std::is_array_v<string_type>)
@ -170,6 +231,8 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
}; };
template<size_t N> template<size_t N>
string_ord(const char (&l)[N]) -> string_ord<decltype(l)>; string_ord(const char (&l)[N]) -> string_ord<decltype(l)>;
template<typename T>
string_ord(T&&) -> string_ord<T>;
/// Used to store all valid command names, so when an invalid one is found, the closest matching one(s) can be suggested to the user in a "did you mean ..." format with the *lowest difference* neighbour(s) to the invalid string first. /// Used to store all valid command names, so when an invalid one is found, the closest matching one(s) can be suggested to the user in a "did you mean ..." format with the *lowest difference* neighbour(s) to the invalid string first.
template<typename T, std::convertible_to<std::string_view> S = std::string_view> template<typename T, std::convertible_to<std::string_view> S = std::string_view>

@ -37,16 +37,20 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
static_assert(_EO_CONSTANT_VALUE(std::string_view{"hello world"}) == std::string_view{"hello world"}, "Bad CONSTANT_VALUE()"); static_assert(_EO_CONSTANT_VALUE(std::string_view{"hello world"}) == std::string_view{"hello world"}, "Bad CONSTANT_VALUE()");
template<typename T, size_t N, typename Array= T[N], typename _I = std::make_index_sequence<N>> template<typename T, size_t N, typename Array= std::array<T, N>, typename _I = std::make_index_sequence<N>>
constexpr decltype(auto) array_literal(const T (&a)[N]) noexcept { constexpr auto array_literal(const T (&a)[N]) noexcept
-> Array
{
constexpr decltype(auto) _array_create = []<size_t... I>(auto const& a, std::index_sequence<I...>) noexcept constexpr decltype(auto) _array_create = []<size_t... I>(auto const& a, std::index_sequence<I...>) noexcept
{ {
return Array { a[I]... }; return Array { a[I]... };
}; };
return _array_create(std::move(a), _I{}); return _array_create(std::move(a), _I{});
} }
template<typename T, size_t N, typename Array= T[N], typename _I = std::make_index_sequence<N>> template<typename T, size_t N, typename Array= std::array<T, N>, typename _I = std::make_index_sequence<N>>
constexpr decltype(auto) array_literal(T (&&a)[N]) noexcept { constexpr auto array_literal(T (&&a)[N]) noexcept
-> Array
{
constexpr decltype(auto) _array_create = []<size_t... I>(auto&& a, std::index_sequence<I...>) noexcept constexpr decltype(auto) _array_create = []<size_t... I>(auto&& a, std::index_sequence<I...>) noexcept
{ {
return Array { std::move(a[I])... }; return Array { std::move(a[I])... };

@ -20,8 +20,12 @@ namespace exopt {
namespace util [[gnu::visibility("internal")]] { namespace util [[gnu::visibility("internal")]] {
namespace { namespace {
constexpr string_ord a("hello world"); constexpr string_ord a("hello world");
constexpr string_ord c{a.view()};
constexpr string_ord b{""}; constexpr string_ord b{""};
static_assert(a.view()[a.view().size()-1], "Levenshtein distance size mismatch for array literals"); static_assert(a.view()[a.view().size()-1], "Levenshtein distance size mismatch for array literals");
static_assert(a.difference_from(c) == 0, "Levenshtein distance mismatch when converting from array literal");
static_assert(a.make_dynamic().view() == c.make_dynamic(), "Levenshtein distance mismatch when converting from array literal to dynamic");
static_assert(c.make_dynamic().view() == a.make_dynamic(), "Levenshtein distance mismatch when converting from std::string to dynamic");
static_assert(b.view().empty(), "Levenshtein distance size mismatch for array literals (empty)"); static_assert(b.view().empty(), "Levenshtein distance size mismatch for array literals (empty)");
static_assert(a.difference_from(b) == (sizeof(a) - sizeof(b)), "Levenshtein distance size mismatch for array literals (calculation)"); static_assert(a.difference_from(b) == (sizeof(a) - sizeof(b)), "Levenshtein distance size mismatch for array literals (calculation)");
} }

Loading…
Cancel
Save