@ -11,6 +11,7 @@
# include <vector>
# include <map>
# include <array>
# include <memory>
# include <span>
# include <tuple>
@ -134,12 +135,17 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
constexpr string_ord ( std : : add_rvalue_reference_t < S > str ) noexcept requires ( ! std : : is_array_v < string_type > )
: m_string ( std : : move ( str ) ) { }
constexpr string_ord ( const char ( & str ) [ sizeof ( string_type ) ] ) requires ( std : : is_array_v < string_type > )
constexpr string_ord ( const char ( & str ) [ sizeof ( string_type ) ] ) noexcept requires ( std : : is_array_v < string_type > )
: string_ord ( std : : move ( str ) , std : : make_index_sequence < sizeof ( string_type ) > { } ) { }
constexpr string_ord ( const char ( & & str ) [ sizeof ( string_type ) ] ) requires ( std : : is_array_v < string_type > )
constexpr string_ord ( const char ( & & str ) [ sizeof ( string_type ) ] ) noexcept requires ( std : : is_array_v < string_type > )
: string_ord ( std : : move ( str ) , std : : make_index_sequence < sizeof ( string_type ) > { } ) { }
constexpr static string_ord from_char_array ( std : : array < char , sizeof ( string_type ) > & & l ) noexcept requires ( std : : is_array_v < string_type > )
{
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 < string_type > ) {
struct OS : public OrderedString {
std : : array < char , sizeof ( string_type ) > 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 < decltype ( str ) > ( 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 < Is . . . > ) noexcept requires ( std : : is_array_v < string_type > )
: m_string { l [ Is ] . . . } { }
template < size_t . . . Is > requires ( sizeof . . . ( Is ) = = sizeof ( string_type ) )
constexpr explicit string_ord ( std : : array < char , sizeof ( string_type ) > & & l , std : : index_sequence < Is . . . > ) noexcept requires ( std : : is_array_v < string_type > )
: m_string { l [ Is ] . . . } { }
string_type m_string ;
} ;
template < size_t N >
@ -234,6 +246,72 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
template < typename T >
string_ord ( T & & ) - > string_ord < T > ;
/// Create a dynamic instance of `string_ord<T>`.
/// This should be passed immediately to a call to `std::make_{unique/shared}` for most cases
template < typename T , typename . . . Args > requires ( std : : is_convertible_v < T , std : : string_view > and std : : is_constructible_v < T , Args . . . > )
constexpr decltype ( auto ) make_dynamic_ordered_string ( Args & & . . . ctor ) noexcept ( std : : is_nothrow_constructible_v < T , Args . . . > )
{
using str = string_ord < T > ;
return str { std : : forward < Args > ( ctor ) . . . } . make_dynamic ( ) ;
}
template < std : : convertible_to < std : : string_view > T >
constexpr decltype ( auto ) make_dynamic_ordered_string ( T & & value ) noexcept ( std : : is_nothrow_move_constructible_v < T > )
{
return string_ord < T > { std : : move ( value ) } . make_dynamic ( ) ;
}
template < std : : convertible_to < std : : string_view > T >
constexpr auto make_unique_ordered_string ( T & & value ) noexcept ( std : : is_nothrow_move_constructible_v < T > )
{
auto & & tmp = make_dynamic_ordered_string < T > ( std : : move ( value ) ) ;
return std : : make_unique < std : : remove_reference_t < decltype ( tmp ) > > ( std : : move ( tmp ) ) ;
}
template < std : : convertible_to < std : : string_view > T >
constexpr auto make_shared_ordered_string ( T & & value ) noexcept ( std : : is_nothrow_move_constructible_v < T > )
{
auto & & tmp = make_dynamic_ordered_string < T > ( std : : move ( value ) ) ;
return std : : make_shared < std : : remove_reference_t < decltype ( tmp ) > > ( std : : move ( tmp ) ) ;
}
template < typename T , typename . . . Args > requires ( std : : is_convertible_v < T , std : : string_view > and std : : is_constructible_v < T , Args . . . > )
constexpr auto make_ordered_string ( Args & & . . . args ) noexcept ( std : : is_nothrow_constructible_v < T , Args . . . > )
{
auto dyn = make_dynamic_ordered_string < T , Args . . . > ( std : : forward < Args > ( args ) . . . ) ;
struct mover {
using type = std : : remove_reference_t < decltype ( dyn ) > ;
using string_type = decltype ( dyn . str ) ;
type value ;
/* constexpr explicit operator auto() noexcept {
if constexpr ( type : : is_array ( ) )
return string_ord < string_type > : : from_char_array ( std : : move ( value . str ) ) ;
else return string_ord < string_type > { std : : move ( value . str ) } ;
} */
constexpr operator std : : shared_ptr < type > ( ) noexcept { return std : : make_shared < type > ( std : : move ( value ) ) ; }
constexpr operator std : : unique_ptr < type > ( ) & & noexcept { return std : : make_unique < type > ( std : : move ( value ) ) ; }
constexpr std : : unique_ptr < type > unique ( ) & & noexcept { return std : : make_unique < type > ( std : : move ( value ) ) ; }
constexpr std : : shared_ptr < type > shared ( ) noexcept { return this - > operator std : : shared_ptr < type > ( ) ; }
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 < typename T , std : : convertible_to < std : : string_view > S = std : : string_view >
using sim_map = std : : map < string_ord < S > , T > ;