@ -100,4 +100,97 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
}
__builtin_unreachable ( ) ;
}
// 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 > )
constexpr auto uninit ( ) noexcept {
union UI {
struct assume { } ;
T value ;
[[no_unique_address]] assume init { } ;
} ;
return UI { } ;
}
template < typename T > requires ( ! std : : is_reference_v < T > )
struct alignas ( T ) maybe_uninit {
using uninit = std : : array < unsigned char , sizeof ( T ) > ;
constexpr maybe_uninit ( ) noexcept { }
constexpr maybe_uninit ( const maybe_uninit & c ) noexcept
: m_uninit ( c . m_uninit ) { }
constexpr maybe_uninit ( maybe_uninit & & m ) noexcept
: m_uninit ( std : : move ( m . m_uninit ) ) { }
constexpr maybe_uninit & operator = ( maybe_uninit const & c ) noexcept
{ m_uninit = c . m_uninit ; return * this ; }
constexpr maybe_uninit & operator = ( maybe_uninit & & c ) noexcept
{ m_uninit = std : : move ( c . m_uninit ) ; return * this ; }
constexpr T & operator = ( T & & value ) noexcept {
m_init = std : : move ( value ) ;
}
constexpr T & operator = ( T const & copy ) noexcept {
m_init = maybe_uninit { copy } ;
}
constexpr T & assume_init ( ) & noexcept = delete ;
constexpr T & & assume_init ( ) & & noexcept { return std : : move ( m_init ) ; }
constexpr T const & assume_init ( ) const & noexcept { return m_init ; }
constexpr T const & & assume_init ( ) const & & noexcept { return m_init ; }
constexpr uninit & data ( ) & noexcept { return m_uninit ; }
constexpr uninit & & data ( ) & & noexcept { return std : : move ( m_uninit ) ; }
constexpr uninit const & data ( ) const & noexcept { return m_uninit ; }
constexpr uninit const & & data ( ) const & & noexcept { return std : : move ( m_uninit ) ; }
constexpr T * get ( ) noexcept { return std : : addressof ( m_init ) ; }
constexpr const T * get ( ) const noexcept { return std : : addressof ( m_init ) ; }
//TODO: accessors, `assume_init_*()`, etc.
constexpr ~ maybe_uninit ( ) noexcept { }
constexpr void assume_init_drop ( ) noexcept ( std : : is_nothrow_destructible_v < T > )
{ m_init . ~ T ( ) ; }
constexpr maybe_uninit < T > init ( T & & value ) noexcept ( std : : is_nothrow_move_constructible_v < T > )
{ return maybe_uninit < T > { std : : move ( value ) , EXPLICIT_INIT_TAG < EXPLICIT_INIT_MOVE > { } } ; }
template < typename . . . Args > requires ( std : : is_constructible_v < T , Args . . . > )
constexpr maybe_uninit < T > init_in_place ( Args & & . . . args ) noexcept ( std : : is_nothrow_constructible_v < T , Args . . . > )
{ return maybe_uninit < T > { EXPLICIT_INIT_TAG < EXPLICIT_INIT_IN_PLACE > { } , std : : forward < Args > ( args ) . . . } ; }
private :
enum EXPLICIT_INIT_TYPE {
EXPLICIT_INIT_IN_PLACE ,
EXPLICIT_INIT_MOVE ,
} ;
template < EXPLICIT_INIT_TYPE >
struct EXPLICIT_INIT_TAG { } ;
constexpr maybe_uninit ( T & & value , EXPLICIT_INIT_TAG < EXPLICIT_INIT_MOVE > ) noexcept ( std : : is_nothrow_move_constructible_v < T > )
: m_init { std : : move ( value ) } { }
template < typename . . . Args > requires ( std : : is_constructible_v < T , Args . . . > )
constexpr maybe_uninit ( EXPLICIT_INIT_TAG < EXPLICIT_INIT_IN_PLACE > _a , Args & & . . . args ) noexcept ( std : : is_nothrow_constructible_v < T , Args . . . > )
: m_init { std : : forward < Args > ( args ) . . . } { ( void ) _a ; }
union {
T m_init ;
[[no_unique_address]] alignas ( T ) uninit m_uninit { } ;
} ;
} ;
namespace {
constexpr std : : string_view ui_test ( ) noexcept {
auto ui = uninit < std : : string_view > ( ) ;
maybe_uninit < std : : string_view > mi ;
ui . init . ~ assume ( ) ;
ui . value = std : : string_view { " Hello " } ;
return std : : move ( ui . value ) ;
}
static_assert ( ui_test ( ) [ 0 ] = = ' H ' , " Bad uninit<T>() " ) ;
}
} }