diff --git a/include/either.hh b/include/either.hh index 3e7a290..07aa830 100644 --- a/include/either.hh +++ b/include/either.hh @@ -1,6 +1,49 @@ #pragma once namespace exopt::types { + +#if 0 +//XXX: Eh, this trait design is NOT GOOD. Figure out a better one + namespace traits { + template + struct impl_clone { + typedef T type; + constexpr static T clone(T const& v) const noexcept(std::is_nothrow_copy_constructible_v) { return v; } + }; + template<> + struct impl_clone {}; + + template struct clone; + + template<> + struct clone : impl_clone {}; + + template + struct clone : impl_clone, T, void> > {}; + + template + struct clone : impl_clone) + -> std::same_as; + }) + , T + , void + > > { + constexpr static T clone(T const& + }; + } + + + template + concept Clone = requires(T const& self) { + typename traits::clone::type; + { traits::clone::clone(self) } noexcept(std::is_nothrow_copy_constructible_v) -> std::same_as; + } or requires(T const& self) { + { self.clone() } noexcept(std::is_nothrow_copy_constructible_v) -> std::same_as; + }; +#endif + namespace either [[gnu::visibility("internal")]] { //TODO: A version with std::shared_ptr instead template//, typename P = T*> @@ -178,5 +221,5 @@ namespace exopt::types { /// RC-lifetime managed Cow template - using AutoCow = Cow>; + using RcCow = Cow>; } diff --git a/include/leven.h b/include/leven.h index 9b9e8f4..dbb37d3 100644 --- a/include/leven.h +++ b/include/leven.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -134,12 +135,17 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] { constexpr string_ord(std::add_rvalue_reference_t str) noexcept requires(!std::is_array_v) : m_string(std::move(str)) {} - constexpr string_ord(const char (&str)[sizeof(string_type)]) requires(std::is_array_v) + constexpr string_ord(const char (&str)[sizeof(string_type)]) noexcept requires(std::is_array_v) : string_ord(std::move(str), std::make_index_sequence{}) {} - constexpr string_ord(const char (&&str)[sizeof(string_type)]) requires(std::is_array_v) + constexpr string_ord(const char (&&str)[sizeof(string_type)]) noexcept requires(std::is_array_v) : string_ord(std::move(str), std::make_index_sequence{}) {} + constexpr static string_ord from_char_array(std::array&& l) noexcept requires(std::is_array_v) + { + return { std::move(l) }; + } + constexpr string_ord(string_ord const&) = default; constexpr string_ord(string_ord &&) = default; constexpr string_ord& operator=(string_ord const&) = default; @@ -190,6 +196,7 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] { if constexpr(std::is_array_v) { struct OS : public OrderedString { std::array str; + constexpr static bool is_array() noexcept { return true; } constexpr virtual ~OS() = default; constexpr OS(string_type const& str) noexcept : OrderedString(), str(util::array_literal(std::forward(str))) {} @@ -207,6 +214,7 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] { } else { struct OS : public OrderedString { string_type str; + constexpr static bool is_array() noexcept { return false; } constexpr virtual ~OS() = default; constexpr OS(string_type&& str) noexcept : OrderedString(), str(std::move(str)) {} @@ -227,6 +235,10 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] { constexpr string_ord(const char (&&l)[sizeof(string_type)], std::index_sequence) noexcept requires(std::is_array_v) : m_string { l[Is]... } {} + template requires(sizeof...(Is) == sizeof(string_type)) + constexpr explicit string_ord(std::array&& l, std::index_sequence) noexcept requires(std::is_array_v) + : m_string { l[Is]... } {} + string_type m_string; }; template @@ -234,6 +246,72 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] { template string_ord(T&&) -> string_ord; + /// Create a dynamic instance of `string_ord`. + /// This should be passed immediately to a call to `std::make_{unique/shared}` for most cases + template requires(std::is_convertible_v and std::is_constructible_v) + constexpr decltype(auto) make_dynamic_ordered_string(Args&&... ctor) noexcept(std::is_nothrow_constructible_v) + { + using str = string_ord; + return str{ std::forward(ctor)... }.make_dynamic(); + } + template T> + constexpr decltype(auto) make_dynamic_ordered_string(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + return string_ord{ std::move(value) }.make_dynamic(); + } + + template T> + constexpr auto make_unique_ordered_string(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + auto&& tmp = make_dynamic_ordered_string(std::move(value)); + + return std::make_unique>(std::move(tmp)); + } + template T> + constexpr auto make_shared_ordered_string(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + auto&& tmp = make_dynamic_ordered_string(std::move(value)); + + return std::make_shared>(std::move(tmp)); + } + + template requires(std::is_convertible_v and std::is_constructible_v) + constexpr auto make_ordered_string(Args&&... args) noexcept(std::is_nothrow_constructible_v) + { + auto dyn = make_dynamic_ordered_string(std::forward(args)...); + struct mover { + using type = std::remove_reference_t; + using string_type = decltype(dyn.str); + type value; + + /* constexpr explicit operator auto() noexcept { + if constexpr(type::is_array()) + return string_ord::from_char_array(std::move(value.str)); + else return string_ord{ std::move(value.str) }; + }*/ + constexpr operator std::shared_ptr() noexcept { return std::make_shared(std::move(value)); } + constexpr operator std::unique_ptr() && noexcept { return std::make_unique(std::move(value)); } + + constexpr std::unique_ptr unique() && noexcept { return std::make_unique(std::move(value)); } + constexpr std::shared_ptr shared() noexcept { return this-> operator std::shared_ptr(); } + + constexpr ~mover() = default; +/* + constexpr string_type const&& exposed() const&& noexcept requires(!type::is_array()){ return std::move(value.str); } + constexpr string_type const& exposed() const& noexcept requires(!type::is_array()){ return value.str; } + constexpr string_type&& exposed() && noexcept requires(!type::is_array()) { return std::move(value.str); } + constexpr string_type exposed() & noexcept requires(!type::is_array()){ return value.str; } + //constexpr string_type const& exposed() const noexcept { return value.str; } + + constexpr explicit operator type&&() && noexcept { return std::move(value); } + constexpr explicit operator string_type&&() && noexcept requires(!type::is_array()) { return std::move(value.str); } + constexpr explicit operator std::string_view() const noexcept { return { value }; }*/ + + }; + return mover{std::move(dyn)}; + } + + /// 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 S = std::string_view> using sim_map = std::map, T>; diff --git a/src/leven.cpp b/src/leven.cpp index c9a4dcd..1267351 100644 --- a/src/leven.cpp +++ b/src/leven.cpp @@ -22,6 +22,11 @@ namespace exopt { constexpr string_ord a("hello world"); constexpr string_ord c{a.view()}; constexpr string_ord b{""}; + consteval bool check_dynamic() noexcept { + auto d = make_ordered_string("hello").unique(); + return d->size() == (sizeof("hello") -1); + } + static_assert(check_dynamic(), "Levenshtein: Bad dynamic sizing"); 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");