@ -89,6 +89,121 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
return _array_create ( std : : move ( a ) , _I { } ) ;
return _array_create ( std : : move ( a ) , _I { } ) ;
}
}
template < size_t N , typename A = std : : array < char , N > , size_t . . . Idx >
constexpr A substring_literal_as ( const auto & str , std : : index_sequence < Idx . . . > ) noexcept
requires ( requires ( size_t n ) {
{ str [ n ] } noexcept - > std : : convertible_to < char > ;
} )
{
return { str [ Idx ] . . . , ' \n ' } ;
}
template < size_t . . . Idx >
constexpr auto substring_literal ( const auto & str , std : : index_sequence < Idx . . . > ) noexcept
requires ( std : : is_invocable_v < substring_literal_as < sizeof . . . ( Idx ) , std : : array < char , sizeof . . . ( Idx ) > , Idx . . . > , decltype ( str ) , std : : index_sequence < Idx . . . > > )
{ return std : : array { str [ Idx ] . . . , ' \n ' } ; }
template < typename T >
constexpr auto type_name_literal ( ) noexcept
{
constexpr std : : string_view prefix {
# if defined(__clang__)
" [T = "
# elif defined(__GNUC__)
" with T = "
# else
// Fuck MSVC, don't care.
# error Unsupported compiler
# endif
} ;
constexpr std : : string_view suffix { " ] " } ;
constexpr std : : string_view function { __PRETTY_FUNCTION__ } ;
constexpr auto start = function . find ( prefix ) + prefix . size ( ) ;
constexpr auto end = function . rfind ( suffix ) ;
static_assert ( start < end ) ;
constexpr std : : string_view name = function . substr ( start , ( end - start ) ) ;
return substring_literal ( name , std : : make_index_sequence < name . size ( ) > { } ) ;
}
template < typename T >
struct [[gnu::visibility("internal")]] type_name_of {
constexpr static inline auto value = type_name_literal < T > ( ) ;
[[gnu::const]]
consteval operator std : : string_view ( ) const noexcept {
constexpr auto & v = value ;
return std : : string_view { v . data ( ) , v . size ( ) } ;
}
} ;
template < typename T >
constexpr auto type_name ( ) noexcept - > std : : string_view
{
constexpr auto & value = type_name_of < T > : : value ;
return std : : string_view { value . data ( ) , value . size ( ) } ;
}
template < typename T >
constexpr inline auto type_name_v = type_name < T > ( ) ;
template < typename S = std : : string_view , S const & . . . Strs >
class [[gnu::visibility("internal")]] concat_str {
consteval static auto impl ( ) noexcept
{
constexpr size_t len = ( Strs . size ( ) + . . . + 0 ) ;
std : : array < char , len + 1 > arr { } ;
auto append = [ i = 0 , & arr ] ( auto const & s ) mutable {
for ( auto c : s ) arr [ i + + ] = c ;
} ;
( append ( Strs ) , . . . ) ;
arr [ len ] = 0 ;
return arr ;
}
public :
constexpr static inline auto literal = impl ( ) ;
constexpr static inline S value { literal . data ( ) , literal . size ( ) - 1 } ;
} ;
template < std : : string_view const & . . . Ss >
constexpr static inline auto concat_str_v = concat_str < std : : string_view , Ss . . . > : : value ;
template < typename S = std : : string_view >
consteval S concat_strings ( std : : convertible_to < S > auto const & . . . strings ) noexcept
{
return concat_str < S , S { strings } . . . > : : value ;
}
static_assert ( concat_str_v < std : : string_view { " hello " } , std : : string_view { " " } , std : : string_view { " view " } >
= = std : : string_view { " hello view " } , " concat_str_v<>: Concatenated string_view failed " ) ;
template < typename R , typename . . . Args >
constexpr auto map ( auto const & fun , Args & & . . . values ) noexcept ( ( std : : is_nothrow_invocable_v < decltype ( fun ) , Args > & & . . . ) )
requires ( ( std : : is_invocable_v < decltype ( fun ) , Args > & & . . . ) and (
( std : : is_void_v < std : : invoke_result_t < decltype ( fun ) , Args > > | | . . . ) | |
std : : is_constructible_v < R , std : : invoke_result_t < decltype ( fun ) , Args > . . . > ) )
- > std : : conditional_t < ( std : : is_void_v < std : : invoke_result_t < decltype ( fun ) , Args > > | | . . . )
, void
, R >
{
if constexpr ( ( std : : is_void_v < std : : invoke_result_t < decltype ( fun ) , Args > > | | . . . ) ) {
( ( void ) std : : invoke ( fun , values ) , . . . ) ;
} else return { std : : invoke ( fun , values ) . . . } ;
}
/ / XXX : To allow this , we might have to turn ` map ` from a function into a function - object class . . . Eh . \
Or we can just let the user specify ` R ` by using std : : tuple as the lvalue assigned from the call maybe ? Or we might have to change it to a ` template < template < typename . . . Results > , typename . . . Args > ` function - object class ; but that would break the ` void ` case . . . . Eeeehh , can we partial - specialise a template < template into a template < typename ? I don ' t think we can on the surface without helper ' ' trait ' ' templates . . . . Eh . . . . . .
template < typename . . . Args >
using map_tuple = map < std : : tuple < Args . . . > , Args . . . > ;
template < typename Fn , typename . . . Args > requires ( ( std : : is_invocable_v < Fn , Args > & & . . . ) )
constexpr void apply ( const Fn & fun , Args & & . . . values ) noexcept ( ( std : : is_nothrow_invocable_v < Fn , Args > & & . . . ) )
/*-> std::conditional_t< (std::is_void_v<std::invoke_result_t<Fn, Args>> || ...)
, void
, std : : common_type_t < std : : invoke_result_t < Fn , Args > . . . > > */
{ map < void , Args . . . > ( fun , std : : forward < Args > ( values ) . . . ) ; }
struct [[gnu::visibility("internal")]] CTInternalFatalError {
struct [[gnu::visibility("internal")]] CTInternalFatalError {
constexpr CTInternalFatalError ( ) noexcept = default ;
constexpr CTInternalFatalError ( ) noexcept = default ;
constexpr CTInternalFatalError ( CTInternalFatalError const & ) noexcept = default ;
constexpr CTInternalFatalError ( CTInternalFatalError const & ) noexcept = default ;
@ -102,29 +217,33 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
consteval virtual std : : string_view message ( ) const noexcept = 0 ;
consteval virtual std : : string_view message ( ) const noexcept = 0 ;
} ;
} ;
/// Throw a string at runtime, as an `std::runtime_error`.
[[noreturn, gnu::noinline, gnu::cold]]
[[noreturn, gnu::noinline, gnu::cold]]
void throw_runtime ( std : : string_view & & ) ;
void throw_runtime ( std : : string_view & & ) ;
/// Throw a string at runtime, or halt compilation with a `CTInternalFatalError`
[[noreturn]]//, gnu::noinline, gnu::cold]]
[[noreturn]]//, gnu::noinline, gnu::cold]]
constexpr void throw_runtime ( std : : convertible_to < std : : string_view > auto & & msg ) {
constexpr void throw_runtime ( std : : convertible_to < std : : string_view > auto & & msg ) {
std : : string_view view { msg } ;
if consteval {
if consteval {
using CTE = CTInternalFatalError ;
# define CTE CTInternalFatalError
struct CTIFRuntimeError : public CTE {
using S = decltype ( msg ) ;
struct CTIFRuntimeError final : public CTE {
using CTE : : CTE ;
using CTE : : CTE ;
consteval CTIFRuntimeError ( std: : string_view & & view ) noexcept
consteval CTIFRuntimeError ( S & & view ) noexcept
: CTE ( ) , m_message ( std : : move ( view ) ) { }
: CTE ( ) , m_message ( std : : move ( view ) ) { }
consteval std : : string_view message ( ) const noexcept override { return m_message ; }
consteval std : : string_view message ( ) const noexcept override { return { m_message } ; }
constexpr virtual ~ CTIFRuntimeError ( ) noexcept { }
constexpr virtual ~ CTIFRuntimeError ( ) noexcept { }
private :
private :
std: : string_view m_message ;
S m_message ;
} ;
} ;
throw CTIFRuntimeError ( std : : move ( view ) ) ;
# undef CTE
throw CTIFRuntimeError ( std : : move ( msg ) ) ;
} else {
} else {
throw_runtime (std : : move ( view) ) ;
static_cast < void ( std : : string_view & & ) > ( throw_runtime ) ({ std : : move ( msg) } ) ; //XXX: We may have to rename the above function (and make it [[internal]], or refactor to make it a private method of a function-object class `throw_runtime` to avoid ambiguations when constexpr-context calls it with the exact typed argument `std::string_view&&`... Maybe... I'm not really sure.
}
}
__builtin_unreachable ( ) ;
__builtin_unreachable ( ) ;
}
}
// Returns an anonymous union with inavtive field: `T value` and active field `assume init` (no unique address).
// Returns an anonymous union with inavtive field: `T value` and active field `assume init` (no unique address).
template < typename T > requires ( ! std : : is_reference_v < T > )
template < typename T > requires ( ! std : : is_reference_v < T > )
constexpr auto uninit ( ) noexcept {
constexpr auto uninit ( ) noexcept {