@ -6,6 +6,8 @@
# include "pointer.h"
# include "exopt.h"
/// A better std::optional
namespace exopt : : types { namespace optional [ [ gnu : : visibility ( " internal " ) ] ] {
template < typename T >
@ -21,6 +23,8 @@ namespace exopt::types { namespace optional [[gnu::visibility("internal")]] {
constexpr static inline auto sentinel = nullptr ;
} ;
template < typename T >
struct null_optimise < std : : reference_wrapper < T > > { constexpr static inline bool value = true ;
using held_type = T * ;
@ -29,7 +33,89 @@ namespace exopt::types { namespace optional [[gnu::visibility("internal")]] {
constexpr static decltype ( auto ) convert_from_held ( std : : add_rvalue_reference_t < held_type > t ) noexcept { return std : : ref < T > ( * t ) ; }
constexpr static inline auto sentinel = nullptr ;
} ;
} ;
template < typename T >
class null_optimise < boxed : : Box < T > > {
using boxed : : Box ;
using box_t = Box < T > ;
class /*XXX: Shouldn't be needed alignas(box_t)*/ invariant : box_t {
//TODO: See phone notes.
using box_t : : UNSAFE ;
public :
constexpr box_t & operator * ( ) & noexcept { return * static_assert < box_t * > ( this ) ; }
constexpr box_t const & operator * ( ) const & noexcept { return * static_assert < box_t const * > ( this ) ; }
constexpr box_t & & operator * ( ) & & noexcept { return std : : move ( * static_assert < box_t * > ( this ) ) ; }
constexpr box_t const & & operator * ( ) const & & noexcept { return std : : move ( * static_assert < box_t const * > ( this ) ) ; }
constexpr static invariant & & back_conv ( box_t & & b ) noexcept { return static_cast < invariant & & > ( b ) ; }
constexpr static invariant const & back_conv ( box_t const & b ) noexcept { return static_cast < invariant const & > ( b ) ; }
constexpr static invariant & back_conv ( box_t & b ) noexcept { return static_cast < invariant & > ( b ) ; }
constexpr static invariant const & & back_conv ( box_t const & & b ) noexcept { return static_cast < invariant const & & > ( b ) ; }
constexpr invariant ( box_t & & m ) noexcept
: box_t ( UNSAFE , std : : move ( std : : move ( m ) . as_unique ( UNSAFE ) ) ) { }
constexpr invariant ( box_t const & m ) noexcept
: box_t ( UNSAFE , m ) { }
constexpr invariant ( std : : unique_ptr < T > & & m ) noexcept
: box_t ( UNSAFE , std : : move ( m ) ) { }
constexpr invariant ( std : : nullptr_t ) noexcept
: box_t ( UNSAFE , std : : unique_ptr < T > { nullptr } ) { }
constexpr friend auto operator < = > ( invariant const & a , invariant const & b ) noexcept { return ( * a ) . as_unsafe_ptr ( UNSAFE ) < = > ( * b ) . as_unsafe_ptr ( UNSAFE ) ; }
constexpr friend auto operator < = > ( invariant const & a , box_t const & b ) noexcept { return ( * a ) . as_unsafe_ptr ( UNSAFE ) < = > b . as_unsafe_ptr ( UNSAFE ) ; }
constexpr friend auto operator < = > ( invariant const & a , T const * p ) noexcept { return ( * a ) . as_unsafe_ptr ( UNSAFE ) < = > p ; }
constexpr friend auto operator < = > ( invariant const & a , std : : nullptr_t ) noexcept { return ( * a ) . as_unsafe_ptr ( UNSAFE ) < = > nullptr ; }
constexpr invariant & operator = ( box_t & & ) noexcept = delete ;
constexpr invariant & operator = ( box_t const & ) = delete ;
constexpr invariant & operator = ( invariant & & ) noexcept = default ;
constexpr invariant & operator = ( invariant const & ) = default ;
constexpr invariant & operator = ( std : : nullptr_t )
{ box_t : : as_unique ( UNSAFE ) . reset ( ) ; return * this ; }
constexpr invariant & operator = ( T * const & & p )
{ box_t : : as_unique ( UNSAFE ) . reset ( p ) ; return * this ; }
constexpr invariant ( invariant & & m ) noexcept
: invariant ( std : : move ( ( * std : : move ( m ) ) . as_unique ( UNSAFE ) ) ) { }
constexpr invariant ( invariant const & m ) noexcept
: box_t ( UNSAFE , ( * m ) . as_unique ( UNSAFE ) ) { }
constexpr ~ invariant ( ) = default ;
} ;
static_assert ( util : : shares_layout < invariant , box_t > , " invariant (held_type) does not share layout with viewed type (Box<T>) " ) ;
public :
typedef invariant held_type ; // invariant ^: Held internal type.
using type = box_t ; // Box<T>: API seen & operated on type
constexpr static decltype ( auto ) convert_to_held ( type ty ) noexcept { return held_type { std : : move ( ty ) } ; }
constexpr static decltype ( auto ) convert_to_held ( type & ty ) noexcept { return held_type : : back_conv ( ty ) ; }
constexpr static decltype ( auto ) convert_to_held ( type & & ty ) noexcept { return held_type : : back_conv ( std : : move ( ty ) ) ; }
constexpr static decltype ( auto ) convert_to_held ( type const & ty ) noexcept { return held_type : : back_conv ( ty ) ; }
constexpr static decltype ( auto ) convert_to_held ( type const & & ty ) noexcept { return held_type : : back_conv ( std : : move ( ty ) ) ; }
constexpr static type & convert_from_held ( held_type & ty ) noexcept { return * ty ; }
constexpr static type const & & convert_from_held ( held_type const & & ty ) noexcept { return std : : move ( * std : : move ( ty ) ) ; }
constexpr static type & & convert_from_held ( held_type & & ty ) noexcept { return std : : move ( * std : : move ( ty ) ) ; }
constexpr static type const & convert_from_held ( held_type const & ty ) noexcept { return * ty ; }
//TODO: See phone notes.
constexpr static inline auto sentinel = nullptr ;
} ;
# ifdef DEBUG / * We don't want to instantiate `null_optimise<>` *at all* if we don't have to outside of actual real use in `Option<T>`. This check is for development only since Option<Box<T>> is a bit of an awkward developmental case.
Save compile time for release builds , the ` static_assert ` inside the null - opt partial spec for ` . . : : invariant ` ' s layout will be checked if / when ` Option < Box < T > > ` is ever instantiated . This check is the same just assuring it ' s valid for * if * Option < Box < T > > is ever instantiated */
static_assert ( ! requires ( requires { typename boxed : : Box < int > ; } ) or // Skip check if `boxed.h` is not included.
requires ( requires ( null_optimise < boxed : : Box < int > > : : held_type const & held ) {
{ static_cast < boxed : : Box < int > const & > ( held ) } ;
} ) , " Nullopt held_type for Box<T> either has a unneeded and unwanted generated vtable or has invalid alignment, check into that " ) ;
# endif
template < typename T >
struct null_optimise < ptr : : Unique < T > > { constexpr static inline bool value = true ;