1434 lines
38 KiB
C++
1434 lines
38 KiB
C++
//
|
|
// Copyright 2014-2018 by Martin Moene
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
// optional lite is inspired on std::optional by Fernando Cacciola and Andrzej Krzemienski
|
|
// and on expected lite by Martin Moene.
|
|
|
|
#include "optional-main.t.hpp"
|
|
|
|
using namespace nonstd;
|
|
|
|
#if optional_USES_STD_OPTIONAL && defined(__APPLE__)
|
|
# define opt_value( o ) *o
|
|
#else
|
|
# define opt_value( o ) o.value()
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
struct nonpod { nonpod(){} };
|
|
|
|
struct Implicit { int x; Implicit(int v) : x(v) {} };
|
|
struct Explicit { int x; explicit Explicit(int v) : x(v) {} };
|
|
|
|
bool operator==( Implicit a, Implicit b ) { return a.x == b.x; }
|
|
bool operator==( Explicit a, Explicit b ) { return a.x == b.x; }
|
|
|
|
std::ostream & operator<<( std::ostream & os, Implicit i ) { return os << "Implicit:" << i.x; }
|
|
std::ostream & operator<<( std::ostream & os, Explicit e ) { return os << "Explicit:" << e.x; }
|
|
|
|
// ensure comparison of pointers for lest:
|
|
|
|
// const void * lest_nullptr = 0;
|
|
|
|
// The following tracer code originates as Oracle from Optional by
|
|
// Andrzej Krzemienski, https://github.com/akrzemi1/Optional.
|
|
|
|
enum State
|
|
{
|
|
/* 0 */ default_constructed,
|
|
/* 1 */ value_copy_constructed,
|
|
/* 2 */ value_move_constructed,
|
|
/* 3 */ copy_constructed,
|
|
/* 4 */ move_constructed,
|
|
/* 5 */ move_assigned,
|
|
/* 6 */ copy_assigned,
|
|
/* 7 */ value_copy_assigned,
|
|
/* 8 */ value_move_assigned,
|
|
/* 9 */ moved_from,
|
|
/*10 */ value_constructed
|
|
};
|
|
|
|
struct V
|
|
{
|
|
State state;
|
|
int value;
|
|
|
|
V( ) : state( default_constructed ), value( deflt() ) {}
|
|
V( int v ) : state( value_constructed ), value( v ) {}
|
|
|
|
bool operator==( V const & rhs ) const { return state == rhs.state && value == rhs.value; }
|
|
bool operator==( int val ) const { return value == val; }
|
|
|
|
static int deflt() { return 42; }
|
|
};
|
|
|
|
struct S
|
|
{
|
|
State state;
|
|
V value;
|
|
|
|
S( ) : state( default_constructed ) {}
|
|
S( V const & v ) : state( value_copy_constructed ), value( v ) {}
|
|
S( S const & s ) : state( copy_constructed ), value( s.value ) {}
|
|
|
|
S & operator=( V const & v ) { state = value_copy_assigned; value = v; return *this; }
|
|
S & operator=( const S & s ) { state = copy_assigned ; value = s.value; return *this; }
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
S( V && v ) : state( value_move_constructed ), value( std::move( v ) ) { v.state = moved_from; }
|
|
S( S && s ) : state( move_constructed ), value( std::move( s.value ) ) { s.state = moved_from; }
|
|
|
|
S & operator=( V && v ) { state = value_move_assigned ; value = std::move( v ); v.state = moved_from; return *this; }
|
|
S & operator=( S && s ) { state = move_assigned ; value = std::move( s.value ); s.state = moved_from; return *this; }
|
|
#endif
|
|
|
|
bool operator==( S const & rhs ) const { return state == rhs.state && value == rhs.value; }
|
|
};
|
|
|
|
inline std::ostream & operator<<( std::ostream & os, V const & v )
|
|
{
|
|
using lest::to_string;
|
|
return os << "[V:" << to_string( v.value ) << "]";
|
|
}
|
|
|
|
inline std::ostream & operator<<( std::ostream & os, S const & s )
|
|
{
|
|
using lest::to_string;
|
|
return os << "[S:" << to_string( s.value ) << "]";
|
|
}
|
|
|
|
struct NoDefault
|
|
{
|
|
NoDefault( NoDefault const & ) {}
|
|
NoDefault & operator=( NoDefault const & ) { return *this; }
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
NoDefault( NoDefault && ) = default;
|
|
NoDefault & operator=( NoDefault && ) = default;
|
|
#endif
|
|
|
|
private:
|
|
NoDefault();
|
|
};
|
|
|
|
struct CopyOnly
|
|
{
|
|
CopyOnly( CopyOnly const & ) {}
|
|
CopyOnly & operator=( CopyOnly const & ) { return *this; }
|
|
|
|
private:
|
|
CopyOnly();
|
|
#if optional_CPP11_OR_GREATER
|
|
CopyOnly( CopyOnly && ) = delete;
|
|
CopyOnly & operator=( CopyOnly && ) = delete;
|
|
#endif
|
|
};
|
|
|
|
struct MoveOnly
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
MoveOnly( MoveOnly && ) = default;
|
|
MoveOnly & operator=( MoveOnly && ) = default;
|
|
#endif
|
|
|
|
private:
|
|
MoveOnly();
|
|
MoveOnly( MoveOnly const & );
|
|
MoveOnly & operator=( MoveOnly const & );
|
|
};
|
|
|
|
struct NoDefaultCopyMove
|
|
{
|
|
std::string text;
|
|
NoDefaultCopyMove( std::string txt ) : text( txt ) {}
|
|
|
|
private:
|
|
NoDefaultCopyMove();
|
|
NoDefaultCopyMove( NoDefaultCopyMove const & );
|
|
NoDefaultCopyMove & operator=( NoDefaultCopyMove const & );
|
|
#if optional_CPP11_OR_GREATER
|
|
NoDefaultCopyMove( NoDefaultCopyMove && ) = delete;
|
|
NoDefaultCopyMove & operator=( NoDefaultCopyMove && ) = delete;
|
|
#endif
|
|
};
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
struct InitList
|
|
{
|
|
std::vector<int> vec;
|
|
char c;
|
|
S s;
|
|
|
|
InitList( std::initializer_list<int> il, char k, S const & t )
|
|
: vec( il ), c( k ), s( t ) {}
|
|
|
|
InitList( std::initializer_list<int> il, char k, S && t )
|
|
: vec( il ), c( k ), s( std::move( t ) ) {}
|
|
};
|
|
#endif
|
|
|
|
} // anonymous namespace
|
|
|
|
//
|
|
// test specification:
|
|
//
|
|
|
|
CASE( "union: A C++03 union can only contain POD types" )
|
|
{
|
|
union U
|
|
{
|
|
char c;
|
|
#if optional_CPP11_OR_GREATER
|
|
nonpod np;
|
|
#endif
|
|
};
|
|
}
|
|
|
|
//
|
|
// optional member operations:
|
|
//
|
|
|
|
// construction:
|
|
|
|
CASE( "optional: Allows to default construct an empty optional (1a)" )
|
|
{
|
|
optional<int> a;
|
|
|
|
EXPECT( !a );
|
|
}
|
|
|
|
CASE( "optional: Allows to explicitly construct a disengaged, empty optional via nullopt (1b)" )
|
|
{
|
|
optional<int> a( nullopt );
|
|
|
|
EXPECT( !a );
|
|
}
|
|
|
|
CASE( "optional: Allows to default construct an empty optional with a non-default-constructible (1a)" )
|
|
{
|
|
// FAILS: NoDefault nd;
|
|
// FAILS: NoDefaultCopyMove ndcm;
|
|
optional<NoDefault> ond;
|
|
optional<CopyOnly> oco;
|
|
optional<MoveOnly> omo;
|
|
optional<NoDefaultCopyMove> ondcm;
|
|
|
|
EXPECT( !ond );
|
|
EXPECT( !oco );
|
|
EXPECT( !omo );
|
|
EXPECT( !ondcm );
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from empty optional (2)" )
|
|
{
|
|
optional<int> a;
|
|
|
|
optional<int> b( a );
|
|
|
|
EXPECT( !b );
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from empty optional (C++11, 3)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a;
|
|
|
|
optional<int> b( std::move( a ) );
|
|
|
|
EXPECT( !b );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from empty optional, explicit converting (C++11, 4a)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a;
|
|
|
|
optional<Explicit> b{ a };
|
|
|
|
EXPECT( !b );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from empty optional, non-explicit converting (4b)" )
|
|
{
|
|
optional<int> a;
|
|
|
|
optional<Implicit> b( a );
|
|
|
|
EXPECT( !b );
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from empty optional, explicit converting (C++11, 5a)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a;
|
|
|
|
optional<Explicit> b{ std::move( a ) };
|
|
|
|
EXPECT( !b );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from empty optional, non-explicit converting (C++11, 5a)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a;
|
|
|
|
optional<Implicit> b( std::move( a ) );
|
|
|
|
EXPECT( !b );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from non-empty optional (2)" )
|
|
{
|
|
optional<int> a( 7 );
|
|
|
|
optional<int> b( a );
|
|
|
|
EXPECT( b );
|
|
EXPECT( *b == 7 );
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from non-empty optional, explicit converting (C++11, 4a)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a( 7 );
|
|
|
|
optional<Explicit> b{ a };
|
|
|
|
EXPECT( b );
|
|
EXPECT( *b == Explicit{7} );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from non-empty optional, non-explicit converting (4b)" )
|
|
{
|
|
optional<int> a( 7 );
|
|
|
|
optional<Implicit> b( a );
|
|
|
|
EXPECT( b );
|
|
EXPECT( *b == Implicit(7) );
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from non-empty optional (C++11, 3)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a( 7 );
|
|
|
|
optional<int> b( std::move( a ) );
|
|
|
|
EXPECT( b );
|
|
EXPECT( *b == 7 );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from non-empty optional, explicit converting (C++11, 5a)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a( 7 );
|
|
|
|
optional<Explicit> b{ std::move( a ) };
|
|
|
|
EXPECT( b );
|
|
EXPECT( *b == Explicit{7} );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from non-empty optional, non-explicit converting (C++11, 5b)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
optional<int> a( 7 );
|
|
|
|
optional<Implicit> b( std::move( a ) );
|
|
|
|
EXPECT( b );
|
|
EXPECT( *b == Implicit(7) );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
namespace {
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
void use_optional( nonstd::optional<Implicit> ) {}
|
|
#else
|
|
template< typename T >
|
|
void use_optional( T ) {}
|
|
#endif
|
|
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from literal value (8)" )
|
|
{
|
|
use_optional( 7 );
|
|
optional<int> a = 7;
|
|
|
|
EXPECT( a );
|
|
EXPECT( *a == 7 );
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from literal value, converting (8)" )
|
|
{
|
|
use_optional( '7' );
|
|
optional<int> a = '7';
|
|
|
|
EXPECT( a );
|
|
EXPECT( *a == '7' );
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from value (8)" )
|
|
{
|
|
const int i = 7;
|
|
|
|
use_optional( i );
|
|
optional<int> a( i );
|
|
|
|
EXPECT( a );
|
|
EXPECT( *a == 7 );
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-construct from value, converting (8)" )
|
|
{
|
|
const char c = '7';
|
|
|
|
use_optional( c );
|
|
optional<int> a( c );
|
|
|
|
EXPECT( a );
|
|
EXPECT( *a == '7' );
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from value (C++11, 8b)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
|
|
optional<S> a( std::move( s ) );
|
|
|
|
EXPECT( a->value == 7 );
|
|
EXPECT( a->state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from value, explicit converting (C++11, 8a)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
int seven = 7;
|
|
|
|
optional<Explicit> a{ std::move( seven ) };
|
|
|
|
EXPECT( a );
|
|
EXPECT( *a == Explicit{7} );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to move-construct from value, non-explicit converting (C++11, 8b)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
int seven = 7;
|
|
optional<Implicit> a( std::move( seven ) );
|
|
|
|
EXPECT( a );
|
|
EXPECT( *a == Implicit(7) );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to in-place construct from literal value (C++11, 6)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
using pair_t = std::pair<char, int>;
|
|
|
|
optional<pair_t> a( in_place, 'a', 7 );
|
|
|
|
EXPECT( a->first == 'a' );
|
|
EXPECT( a->second == 7 );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to in-place copy-construct from value (C++11, 6)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
char c = 'a'; S s( 7 );
|
|
using pair_t = std::pair<char, S>;
|
|
|
|
optional<pair_t> a( in_place, c, s );
|
|
|
|
EXPECT( a->first == 'a' );
|
|
EXPECT( a->second.value == 7 );
|
|
#if optional_USES_STD_OPTIONAL
|
|
EXPECT( a->second.state == copy_constructed );
|
|
#else
|
|
EXPECT( a->second.state == move_constructed );
|
|
#endif
|
|
EXPECT( s.state != moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to in-place move-construct from value (C++11, 6)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
char c = 'a'; S s( 7 );
|
|
using pair_t = std::pair<char, S>;
|
|
|
|
optional<pair_t> a( in_place, c, std::move( s ) );
|
|
|
|
EXPECT( a->first == 'a' );
|
|
EXPECT( a->second.value == 7 );
|
|
EXPECT( a->second.state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to in-place copy-construct from initializer-list (C++11, 7)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
optional<InitList> a( in_place, { 7, 8, 9, }, 'a', s );
|
|
|
|
EXPECT( a->vec[0] == 7 );
|
|
EXPECT( a->vec[1] == 8 );
|
|
EXPECT( a->vec[2] == 9 );
|
|
EXPECT( a->c == 'a');
|
|
EXPECT( a->s.value == 7 );
|
|
#if optional_USES_STD_OPTIONAL
|
|
EXPECT( a->s.state == copy_constructed );
|
|
#else
|
|
EXPECT( a->s.state == move_constructed );
|
|
#endif
|
|
EXPECT( s.state != moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to in-place move-construct from initializer-list (C++11, 7)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
optional<InitList> a( in_place, { 7, 8, 9, }, 'a', std::move( s ) );
|
|
|
|
EXPECT( a->vec[0] == 7 );
|
|
EXPECT( a->vec[1] == 8 );
|
|
EXPECT( a->vec[2] == 9 );
|
|
EXPECT( a->c == 'a' );
|
|
EXPECT( a->s.value == 7 );
|
|
EXPECT( a->s.state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
// assignment:
|
|
|
|
CASE( "optional: Allows to assign nullopt to disengage (1)" )
|
|
{
|
|
optional<int> a( 7 );
|
|
|
|
a = nullopt;
|
|
|
|
EXPECT( !a );
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-assign from/to engaged and disengaged optionals (2)" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<int> d1;
|
|
optional<int> d2;
|
|
optional<int> e1( 123 );
|
|
optional<int> e2( 987 );
|
|
|
|
SECTION( "a disengaged optional assigned nullopt remains empty" ) {
|
|
d1 = nullopt;
|
|
EXPECT( !d1 );
|
|
}
|
|
SECTION( "a disengaged optional assigned an engaged optional obtains its value" ) {
|
|
d1 = e1;
|
|
EXPECT( d1 );
|
|
EXPECT( *d1 == 123 );
|
|
}
|
|
SECTION( "an engaged optional assigned an engaged optional obtains its value" ) {
|
|
e1 = e2;
|
|
EXPECT( e1 );
|
|
EXPECT( *e1 == 987 );
|
|
}
|
|
SECTION( "an engaged optional assigned nullopt becomes empty" ) {
|
|
e1 = nullopt;
|
|
EXPECT( !e1 );
|
|
}
|
|
SECTION( "a disengaged optional assigned a disengaged optional remains empty" ) {
|
|
d1 = d2;
|
|
EXPECT( !d1 );
|
|
}}
|
|
}
|
|
|
|
CASE( "optional: Allows to move-assign from/to engaged and disengaged optionals (C++11, 3)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
SETUP( "" ) {
|
|
optional<int> d1;
|
|
optional<int> d2;
|
|
optional<int> e1( 123 );
|
|
optional<int> e2( 987 );
|
|
|
|
SECTION( "a disengaged optional assigned nullopt remains empty" ) {
|
|
d1 = std::move( nullopt );
|
|
EXPECT( !d1 );
|
|
}
|
|
SECTION( "a disengaged optional assigned an engaged optional obtains its value" ) {
|
|
d1 = std::move( e1);
|
|
EXPECT( d1 );
|
|
EXPECT( *d1 == 123 );
|
|
}
|
|
SECTION( "an engaged optional assigned an engaged optional obtains its value" ) {
|
|
e1 = std::move( e2 );
|
|
EXPECT( e1 );
|
|
EXPECT( *e1 == 987 );
|
|
}
|
|
SECTION( "an engaged optional assigned nullopt becomes empty" ) {
|
|
e1 = std::move( nullopt );
|
|
EXPECT( !e1 );
|
|
}
|
|
SECTION( "a disengaged optional assigned a disengaged optional remains empty" ) {
|
|
d1 = std::move( d2);
|
|
EXPECT( !d1 );
|
|
}}
|
|
#else
|
|
EXPECT( !!"optional: move-assignment is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-assign from/to engaged and disengaged optionals, converting, (5)" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<int> d1;
|
|
optional<char> d2;
|
|
optional<int> e1( 123 );
|
|
optional<char> e2( '7' );
|
|
|
|
SECTION( "a disengaged optional assigned an engaged optional obtains its value, converting" ) {
|
|
d1 = e2;
|
|
EXPECT( d1 );
|
|
EXPECT( *d1 == '7' );
|
|
}
|
|
SECTION( "an engaged optional assigned an engaged optional obtains its value, converting" ) {
|
|
e1 = e2;
|
|
EXPECT( e1 );
|
|
EXPECT( *e1 == '7' );
|
|
}
|
|
SECTION( "an engaged optional assigned a disengaged optional becomes empty, converting" ) {
|
|
e1 = d2;
|
|
EXPECT( !e1 );
|
|
}
|
|
SECTION( "a disengaged optional assigned a disengaged optional remains empty, converting" ) {
|
|
d1 = d2;
|
|
EXPECT( !d1 );
|
|
}}
|
|
}
|
|
|
|
CASE( "optional: Allows to move-assign from/to engaged and disengaged optionals, converting (C++11, 6)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
SETUP( "" ) {
|
|
optional<int> d1;
|
|
optional<char> d2;
|
|
optional<int> e1( 123 );
|
|
optional<char> e2( '7' );
|
|
|
|
SECTION( "a disengaged optional assigned an engaged optional obtains its value, converting" ) {
|
|
d1 = std::move( e2 );
|
|
EXPECT( d1 );
|
|
EXPECT( *d1 == '7' );
|
|
}
|
|
SECTION( "an engaged optional assigned an engaged optional obtains its value, converting" ) {
|
|
e1 = std::move( e2 );
|
|
EXPECT( e1 );
|
|
EXPECT( *e1 == '7' );
|
|
}
|
|
SECTION( "an engaged optional assigned a disengaged optional becomes empty, converting" ) {
|
|
e1 = std::move( d2 );
|
|
EXPECT( !e1 );
|
|
}
|
|
SECTION( "a disengaged optional assigned a disengaged optional remains empty, converting" ) {
|
|
d1 = std::move( d2 );
|
|
EXPECT( !d1 );
|
|
}}
|
|
#else
|
|
EXPECT( !!"optional: move-assignment is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-assign from literal value (4)" )
|
|
{
|
|
optional<int> a;
|
|
|
|
a = 7;
|
|
|
|
EXPECT( *a == 7 );
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-assign from value (4)" )
|
|
{
|
|
const int i = 7;
|
|
optional<int> a;
|
|
|
|
a = i;
|
|
|
|
EXPECT( *a == i );
|
|
}
|
|
|
|
CASE( "optional: Allows to move-assign from value (C++11, 4)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
optional<S> a;
|
|
|
|
a = std::move( s );
|
|
|
|
EXPECT( a->value == 7 );
|
|
EXPECT( a->state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: move-assign is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-emplace content from arguments (C++11, 7)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
using pair_t = std::pair<char, S>;
|
|
S s( 7 );
|
|
optional<pair_t> a;
|
|
|
|
a.emplace( 'a', s );
|
|
|
|
EXPECT( a->first == 'a' );
|
|
EXPECT( a->second.value == 7 );
|
|
EXPECT( a->second.state == copy_constructed );
|
|
EXPECT( s.state != moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to move-emplace content from arguments (C++11, 7)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
using pair_t = std::pair<char, S>;
|
|
S s( 7 );
|
|
optional<pair_t> a;
|
|
|
|
a.emplace( 'a', std::move( s ) );
|
|
|
|
EXPECT( a->first == 'a' );
|
|
EXPECT( a->second.value == 7 );
|
|
EXPECT( a->second.state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to copy-emplace content from intializer-list and arguments (C++11, 8)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
optional<InitList> a;
|
|
|
|
a.emplace( { 7, 8, 9, }, 'a', s );
|
|
|
|
EXPECT( a->vec[0] == 7 );
|
|
EXPECT( a->vec[1] == 8 );
|
|
EXPECT( a->vec[2] == 9 );
|
|
EXPECT( a->c == 'a' );
|
|
EXPECT( a->s.value == 7 );
|
|
EXPECT( a->s.state == copy_constructed );
|
|
EXPECT( s.state != moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to move-emplace content from intializer-list and arguments (C++11, 8)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
optional<InitList> a;
|
|
|
|
a.emplace( { 7, 8, 9, }, 'a', std::move( s ) );
|
|
|
|
EXPECT( a->vec[0] == 7 );
|
|
EXPECT( a->vec[1] == 8 );
|
|
EXPECT( a->vec[2] == 9 );
|
|
EXPECT( a->c == 'a' );
|
|
EXPECT( a->s.value == 7 );
|
|
EXPECT( a->s.state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
// swap:
|
|
|
|
CASE( "optional: Allows to swap with other optional (member)" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<int> d1;
|
|
optional<int> d2;
|
|
optional<int> e1( 42 );
|
|
optional<int> e2( 7 );
|
|
|
|
SECTION( "swap disengaged with disengaged optional" ) {
|
|
d1.swap( d2 );
|
|
EXPECT( !d1 );
|
|
}
|
|
SECTION( "swap engaged with engaged optional" ) {
|
|
e1.swap( e2 );
|
|
EXPECT( e1 );
|
|
EXPECT( e2 );
|
|
EXPECT( *e1 == 7 );
|
|
EXPECT( *e2 == 42 );
|
|
}
|
|
SECTION( "swap disengaged with engaged optional" ) {
|
|
d1.swap( e1 );
|
|
EXPECT( d1 );
|
|
EXPECT( !e1 );
|
|
EXPECT( *d1 == 42 );
|
|
}
|
|
SECTION( "swap engaged with disengaged optional" ) {
|
|
e1.swap( d1 );
|
|
EXPECT( d1 );
|
|
EXPECT( !e1 );
|
|
EXPECT( *d1 == 42 );
|
|
}}
|
|
}
|
|
|
|
// observers:
|
|
|
|
CASE( "optional: Allows to obtain value via operator->()" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<Implicit> e( Implicit( 42 ) );
|
|
optional<Implicit> const ce( Implicit( 42 ) );
|
|
|
|
SECTION( "operator->() yields pointer to value (const)" ) {
|
|
EXPECT( ce->x == 42 );
|
|
}
|
|
SECTION( "operator->() yields pointer to value (non-const)" ) {
|
|
e->x = 7;
|
|
EXPECT( e->x == 7 );
|
|
}}
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain moved-value via operator->() (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
SETUP( "" ) {
|
|
optional<Implicit> e( Implicit( 42 ) );
|
|
optional<Implicit> const ce( Implicit( 42 ) );
|
|
|
|
SECTION( "operator->() yields pointer to value (const)" ) {
|
|
EXPECT( std::move( ce )->x == 42 );
|
|
}
|
|
SECTION( "operator->() yields pointer to value (non-const)" ) {
|
|
e->x = 7;
|
|
EXPECT( std::move( e )->x == 7 );
|
|
}}
|
|
#else
|
|
EXPECT( !!"optional: move-semantics are not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain value via operator*()" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<int> e( 42 );
|
|
optional<int> const ce( 42 );
|
|
|
|
SECTION( "operator*() yields value (const)" ) {
|
|
EXPECT( *ce == 42 );
|
|
}
|
|
SECTION( "operator*() yields value (non-const)" ) {
|
|
*e = 7;
|
|
EXPECT( *e == 7 );
|
|
}}
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain moved-value via operator*() (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
SETUP( "" ) {
|
|
optional<int> e( 42 );
|
|
optional<int> const ce( 42 );
|
|
|
|
SECTION( "operator*() yields value (const)" ) {
|
|
EXPECT( *(std::move( ce )) == 42 );
|
|
}
|
|
SECTION( "operator*() yields value (non-const)" ) {
|
|
*e = 7;
|
|
EXPECT( *(std::move( e )) == 7 );
|
|
}}
|
|
#else
|
|
EXPECT( !!"optional: move-semantics are not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain has_value() via operator bool()" )
|
|
{
|
|
optional<int> a;
|
|
optional<int> b( 7 );
|
|
|
|
EXPECT_NOT( a );
|
|
EXPECT( b );
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain value via value()" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<int> e( 42 );
|
|
optional<int> const ce( 42 );
|
|
|
|
SECTION( "value() yields value (const)" ) {
|
|
EXPECT( opt_value( ce ) == 42 );
|
|
}
|
|
SECTION( "value() yields value (non-const)" ) {
|
|
EXPECT( opt_value( e ) == 42 );
|
|
}}
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain moved-value via value() (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
SETUP( "" ) {
|
|
optional<int> e( 42 );
|
|
optional<int> const ce( 42 );
|
|
|
|
SECTION( "value() yields value (const)" ) {
|
|
EXPECT( opt_value( std::move( ce ) ) == 42 );
|
|
}
|
|
SECTION( "value() yields value (non-const)" ) {
|
|
EXPECT( opt_value( std::move( e ) ) == 42 );
|
|
}}
|
|
#else
|
|
EXPECT( !!"optional: move-semantics are not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain value or default via value_or()" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<int> d;
|
|
optional<int> e( 42 );
|
|
|
|
SECTION( "value_or( 7 ) yields value for non-empty optional" ) {
|
|
EXPECT( e.value_or( 7 ) == 42 );
|
|
}
|
|
SECTION( "value_or( 7 ) yields default for empty optional" ) {
|
|
EXPECT( d.value_or( 7 ) == 7 );
|
|
}}
|
|
}
|
|
|
|
CASE( "optional: Allows to obtain moved-value or moved-default via value_or() (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
SETUP( "" ) {
|
|
optional<int> d;
|
|
optional<int> e( 42 );
|
|
optional<std::string> ds;
|
|
optional<std::string> es("77");
|
|
|
|
SECTION("for l-values") {
|
|
EXPECT( d.value_or( 7 ) == 7 );
|
|
EXPECT( e.value_or( 7 ) == 42 );
|
|
EXPECT( ds.value_or("7") == "7" );
|
|
EXPECT( es.value_or("7") == "77" );
|
|
EXPECT_NOT( es->empty() ); // see issue-60
|
|
}
|
|
SECTION("for r-values") {
|
|
EXPECT( std::move( d ).value_or( 7 ) == 7 );
|
|
EXPECT( std::move( e ).value_or( 7 ) == 42 );
|
|
EXPECT( std::move( ds ).value_or("7") == "7" );
|
|
EXPECT( std::move( es ).value_or("7") == "77" );
|
|
}}
|
|
#else
|
|
EXPECT( !!"optional: move-semantics are not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Throws bad_optional_access at disengaged access" )
|
|
{
|
|
#if optional_USES_STD_OPTIONAL && defined(__APPLE__)
|
|
EXPECT( true );
|
|
#else
|
|
SETUP( "" ) {
|
|
optional<int> d;
|
|
optional<int> const cd;
|
|
|
|
SECTION("for l-values") {
|
|
EXPECT_THROWS_AS( d.value(), bad_optional_access );
|
|
EXPECT_THROWS_AS( cd.value(), bad_optional_access );
|
|
}
|
|
# if optional_CPP11_OR_GREATER
|
|
SECTION("for r-values") {
|
|
EXPECT_THROWS_AS( std::move( d ).value(), bad_optional_access );
|
|
EXPECT_THROWS_AS( std::move( cd ).value(), bad_optional_access );
|
|
}
|
|
# endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Throws bad_optional_access with non-empty what()" )
|
|
{
|
|
try
|
|
{
|
|
optional<int> d;
|
|
(void) d.value();
|
|
}
|
|
catch( bad_optional_access const & e )
|
|
{
|
|
EXPECT( ! std::string( e.what() ).empty() );
|
|
}
|
|
}
|
|
|
|
// modifiers:
|
|
|
|
CASE( "optional: Allows to reset content" )
|
|
{
|
|
optional<int> a = 7;
|
|
|
|
a.reset();
|
|
|
|
EXPECT_NOT( a.has_value() );
|
|
}
|
|
|
|
// desctruction:
|
|
|
|
namespace destruction {
|
|
|
|
struct S
|
|
{
|
|
static void reset() { ctor_count() = 0; dtor_count() = 0; }
|
|
static int & ctor_count() { static int i = 0; return i; }
|
|
static int & dtor_count() { static int i = 0; return i; }
|
|
|
|
S( int /*i*/ ) { ++ctor_count(); }
|
|
S( char /*c*/, int /*i*/ ) { ++ctor_count(); }
|
|
S( S const & ) { ++ctor_count(); }
|
|
#if optional_CPP11_OR_GREATER
|
|
S( S&& ) {}
|
|
#endif
|
|
~S() { ++dtor_count(); }
|
|
};
|
|
} // namespace destruct
|
|
|
|
CASE( "optional: Ensure object is destructed only once (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
using destruction::S;
|
|
|
|
SETUP( "- Reset ctor & dtor counts" ) {
|
|
|
|
S::reset();
|
|
|
|
SECTION( "- Destruction with direct initialize (C++11)" )
|
|
{
|
|
{
|
|
optional<S> s( 7 );
|
|
|
|
EXPECT( s.has_value() );
|
|
EXPECT( S::dtor_count() == 0 );
|
|
}
|
|
EXPECT( S::dtor_count() == 1 );
|
|
}
|
|
SECTION( "- Destruction with emplace (C++11)" )
|
|
{
|
|
{
|
|
optional<S> s;
|
|
|
|
EXPECT( S::dtor_count() == 0 );
|
|
|
|
s.emplace( 'c', 42 );
|
|
|
|
EXPECT( S::dtor_count() == 0 );
|
|
}
|
|
EXPECT( S::dtor_count() == 1 );
|
|
}}
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "optional: Ensure balanced construction-destruction (C++98)" )
|
|
{
|
|
using destruction::S;
|
|
|
|
SETUP( "- Reset ctor & dtor counts" ) {
|
|
|
|
S::reset();
|
|
|
|
SECTION( "- Destruction with direct initialize (C++98)" )
|
|
{
|
|
{
|
|
optional<S> s( 7 );
|
|
|
|
EXPECT( s.has_value() );
|
|
EXPECT( S::ctor_count() == S::dtor_count() + 1 );
|
|
}
|
|
EXPECT( S::ctor_count() == S::dtor_count() );
|
|
}}
|
|
}
|
|
|
|
//
|
|
// optional non-member functions:
|
|
//
|
|
|
|
CASE( "optional: Allows to swaps engage state and values (non-member)" )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<int> d1;
|
|
optional<int> d2;
|
|
optional<int> e1( 42 );
|
|
optional<int> e2( 7 );
|
|
|
|
SECTION( "swap disengaged with disengaged optional" ) {
|
|
swap( d1, d2 );
|
|
EXPECT( !d1 );
|
|
}
|
|
SECTION( "swap engaged with engaged optional" ) {
|
|
swap( e1, e2 );
|
|
EXPECT( e1 );
|
|
EXPECT( e2 );
|
|
EXPECT( *e1 == 7 );
|
|
EXPECT( *e2 == 42 );
|
|
}
|
|
SECTION( "swap disengaged with engaged optional" ) {
|
|
swap( d1, e1 );
|
|
EXPECT( d1 );
|
|
EXPECT( !e1 );
|
|
EXPECT( *d1 == 42 );
|
|
}
|
|
SECTION( "swap engaged with disengaged optional" ) {
|
|
swap( e1, d1 );
|
|
EXPECT( d1 );
|
|
EXPECT( !e1 );
|
|
EXPECT( *d1 == 42 );
|
|
}}
|
|
}
|
|
|
|
template< typename R, typename S, typename T >
|
|
void relop( lest::env & lest_env )
|
|
{
|
|
SETUP( "" ) {
|
|
optional<R> d;
|
|
optional<S> e1( 6 );
|
|
optional<T> e2( 7 );
|
|
|
|
SECTION( "engaged == engaged" ) { EXPECT( e1 == e1 ); }
|
|
SECTION( "engaged == disengaged" ) { EXPECT( !(e1 == d ) ); }
|
|
SECTION( "disengaged == engaged" ) { EXPECT( !(d == e1) ); }
|
|
|
|
SECTION( "engaged != engaged" ) { EXPECT( e1 != e2 ); }
|
|
SECTION( "engaged != disengaged" ) { EXPECT( e1 != d ); }
|
|
SECTION( "disengaged != engaged" ) { EXPECT( d != e2 ); }
|
|
|
|
SECTION( "engaged < engaged" ) { EXPECT( e1 < e2 ); }
|
|
SECTION( "engaged < disengaged" ) { EXPECT( !(e1 < d ) ); }
|
|
SECTION( "disengaged < engaged" ) { EXPECT( d < e2 ); }
|
|
|
|
SECTION( "engaged <= engaged" ) { EXPECT( e1 <= e1 ); }
|
|
SECTION( "engaged <= engaged" ) { EXPECT( e1 <= e2 ); }
|
|
SECTION( "engaged <= disengaged" ) { EXPECT( !(e1 <= d ) ); }
|
|
SECTION( "disengaged <= engaged" ) { EXPECT( d <= e2 ); }
|
|
|
|
SECTION( "engaged > engaged" ) { EXPECT( e2 > e1 ); }
|
|
SECTION( "engaged > disengaged" ) { EXPECT( e2 > d ); }
|
|
SECTION( "disengaged > engaged" ) { EXPECT( !(d > e1) ); }
|
|
|
|
SECTION( "engaged >= engaged" ) { EXPECT( e1 >= e1 ); }
|
|
SECTION( "engaged >= engaged" ) { EXPECT( e2 >= e1 ); }
|
|
SECTION( "engaged >= disengaged" ) { EXPECT( e2 >= d ); }
|
|
SECTION( "disengaged >= engaged" ) { EXPECT( !(d >= e1) ); }
|
|
|
|
SECTION( "disengaged == nullopt" ) { EXPECT( (d == nullopt) ); }
|
|
SECTION( "nullopt == disengaged" ) { EXPECT( (nullopt == d ) ); }
|
|
SECTION( "engaged == nullopt" ) { EXPECT( (e1 != nullopt) ); }
|
|
SECTION( "nullopt == engaged" ) { EXPECT( (nullopt != e1 ) ); }
|
|
SECTION( "disengaged == nullopt" ) { EXPECT( !(d < nullopt) ); }
|
|
SECTION( "nullopt == disengaged" ) { EXPECT( !(nullopt < d ) ); }
|
|
SECTION( "disengaged == nullopt" ) { EXPECT( (d <= nullopt) ); }
|
|
SECTION( "nullopt == disengaged" ) { EXPECT( (nullopt <= d ) ); }
|
|
SECTION( "disengaged == nullopt" ) { EXPECT( !(d > nullopt) ); }
|
|
SECTION( "nullopt == disengaged" ) { EXPECT( !(nullopt > d ) ); }
|
|
SECTION( "disengaged == nullopt" ) { EXPECT( (d >= nullopt) ); }
|
|
SECTION( "nullopt == disengaged" ) { EXPECT( (nullopt >= d ) ); }
|
|
|
|
SECTION( "engaged == value" ) { EXPECT( e1 == 6 ); }
|
|
SECTION( "value == engaged" ) { EXPECT( 6 == e1 ); }
|
|
SECTION( "engaged != value" ) { EXPECT( e1 != 7 ); }
|
|
SECTION( "value != engaged" ) { EXPECT( 6 != e2 ); }
|
|
SECTION( "engaged < value" ) { EXPECT( e1 < 7 ); }
|
|
SECTION( "value < engaged" ) { EXPECT( 6 < e2 ); }
|
|
SECTION( "engaged <= value" ) { EXPECT( e1 <= 7 ); }
|
|
SECTION( "value <= engaged" ) { EXPECT( 6 <= e2 ); }
|
|
SECTION( "engaged > value" ) { EXPECT( e2 > 6 ); }
|
|
SECTION( "value > engaged" ) { EXPECT( 7 > e1 ); }
|
|
SECTION( "engaged >= value" ) { EXPECT( e2 >= 6 ); }
|
|
SECTION( "value >= engaged" ) { EXPECT( 7 >= e1 ); }
|
|
}
|
|
}
|
|
|
|
CASE( "optional: Provides relational operators (non-member)" )
|
|
{
|
|
relop<int, int, int>( lest_env );
|
|
}
|
|
|
|
CASE( "optional: Provides mixed-type relational operators (non-member)" )
|
|
{
|
|
relop<char, int, long>( lest_env );
|
|
}
|
|
|
|
CASE( "make_optional: Allows to copy-construct optional" )
|
|
{
|
|
S s( 7 );
|
|
|
|
EXPECT( make_optional( s )->value == 7 );
|
|
EXPECT( s.state != moved_from );
|
|
}
|
|
|
|
CASE( "make_optional: Allows to move-construct optional (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
|
|
EXPECT( make_optional( std::move( s ) )->value == 7 );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: move-construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "make_optional: Allows to in-place copy-construct optional from arguments (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
using pair_t = std::pair<char, S>;
|
|
|
|
S s( 7);
|
|
auto a = make_optional<pair_t>( 'a', s );
|
|
|
|
EXPECT( a->first == 'a' );
|
|
EXPECT( a->second.value == 7 );
|
|
#if optional_USES_STD_OPTIONAL
|
|
EXPECT( a->second.state == copy_constructed );
|
|
#else
|
|
EXPECT( a->second.state == move_constructed );
|
|
#endif
|
|
EXPECT( s.state != moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "make_optional: Allows to in-place move-construct optional from arguments (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
using pair_t = std::pair<char, S>;
|
|
|
|
S s( 7 );
|
|
auto a = make_optional<pair_t>( 'a', std::move( s ) );
|
|
|
|
EXPECT( a->first == 'a' );
|
|
EXPECT( a->second.value == 7 );
|
|
EXPECT( a->second.state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "make_optional: Allows to in-place copy-construct optional from initializer-list and arguments (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
auto a = make_optional<InitList>( { 7, 8, 9, }, 'a', s );
|
|
|
|
EXPECT( a->vec[0] == 7 );
|
|
EXPECT( a->vec[1] == 8 );
|
|
EXPECT( a->vec[2] == 9 );
|
|
EXPECT( a->c == 'a' );
|
|
EXPECT( a->s.value == 7 );
|
|
#if optional_USES_STD_OPTIONAL
|
|
EXPECT( a->s.state == copy_constructed );
|
|
#else
|
|
EXPECT( a->s.state == move_constructed );
|
|
#endif
|
|
EXPECT( s.state != moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "make_optional: Allows to in-place move-construct optional from initializer-list and arguments (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
S s( 7 );
|
|
auto a = make_optional<InitList>( { 7, 8, 9, }, 'a', std::move( s ) );
|
|
|
|
EXPECT( a->vec[0] == 7 );
|
|
EXPECT( a->vec[1] == 8 );
|
|
EXPECT( a->vec[2] == 9 );
|
|
EXPECT( a->c == 'a' );
|
|
EXPECT( a->s.value == 7 );
|
|
EXPECT( a->s.state == move_constructed );
|
|
EXPECT( s.state == moved_from );
|
|
#else
|
|
EXPECT( !!"optional: in-place construction is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "std::hash<>: Allows to obtain hash (C++11)" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
const auto a = optional<int>( 7 );
|
|
const auto b = optional<int>( 7 );
|
|
|
|
EXPECT( std::hash<optional<int>>{}( a ) == std::hash<optional<int>>{}( b ) );
|
|
#else
|
|
EXPECT( !!"std::hash<>: std::hash<> is not available (no C++11)" );
|
|
#endif
|
|
}
|
|
|
|
CASE( "tweak header: reads tweak header if supported " "[tweak]" )
|
|
{
|
|
#if optional_HAVE_TWEAK_HEADER
|
|
EXPECT( OPTIONAL_TWEAK_VALUE == 42 );
|
|
#else
|
|
EXPECT( !!"Tweak header is not available (optional_HAVE_TWEAK_HEADER: 0)." );
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Negative tests:
|
|
//
|
|
|
|
//
|
|
// Tests that print information:
|
|
//
|
|
|
|
struct Struct{ Struct(){} };
|
|
|
|
#if !defined(optional_FEATURE_MAX_ALIGN_HACK) || !optional_FEATURE_MAX_ALIGN_HACK
|
|
|
|
#define optional_OUTPUT_ALIGNMENT_OF( type ) \
|
|
"alignment_of<" #type ">: " << \
|
|
alignment_of<type>::value << "\n" <<
|
|
|
|
CASE("alignment_of: Show alignment of various types"
|
|
"[.]" )
|
|
{
|
|
#if optional_CPP11_OR_GREATER
|
|
using std::alignment_of;
|
|
#else
|
|
using ::nonstd::optional_lite::detail::alignment_of;
|
|
#endif
|
|
|
|
std::cout <<
|
|
optional_OUTPUT_ALIGNMENT_OF( char )
|
|
optional_OUTPUT_ALIGNMENT_OF( short )
|
|
optional_OUTPUT_ALIGNMENT_OF( int )
|
|
optional_OUTPUT_ALIGNMENT_OF( long )
|
|
optional_OUTPUT_ALIGNMENT_OF( float )
|
|
optional_OUTPUT_ALIGNMENT_OF( double )
|
|
optional_OUTPUT_ALIGNMENT_OF( long double )
|
|
optional_OUTPUT_ALIGNMENT_OF( Struct )
|
|
"";
|
|
}
|
|
#undef optional_OUTPUT_ALIGNMENT_OF
|
|
#endif
|
|
|
|
#define optional_OUTPUT_SIZEOF( type ) \
|
|
"sizeof( optional<" #type "> ): " << \
|
|
sizeof( optional< type> ) << " (" << sizeof(type) << ")\n" <<
|
|
|
|
CASE("storage_t: Show sizeof various optionals"
|
|
"[.]" )
|
|
{
|
|
std::cout <<
|
|
#if !optional_USES_STD_OPTIONAL
|
|
"sizeof( nonstd::optional_lite::detail::storage_t<char> ): " <<
|
|
sizeof( nonstd::optional_lite::detail::storage_t<char> ) << "\n" <<
|
|
#endif
|
|
optional_OUTPUT_SIZEOF( char )
|
|
optional_OUTPUT_SIZEOF( short )
|
|
optional_OUTPUT_SIZEOF( int )
|
|
optional_OUTPUT_SIZEOF( long )
|
|
optional_OUTPUT_SIZEOF( float )
|
|
optional_OUTPUT_SIZEOF( double )
|
|
optional_OUTPUT_SIZEOF( long double )
|
|
optional_OUTPUT_SIZEOF( Struct )
|
|
"";
|
|
}
|
|
#undef optional_OUTPUT_SIZEOF
|
|
|
|
//
|
|
// Issues:
|
|
//
|
|
|
|
CASE( "optional: isocpp-lib: CH 3, p0032r2 -- let's not have too clever tags" "[.issue-1]" )
|
|
{
|
|
EXPECT( false );
|
|
#if 0
|
|
optional< optional< optional<int> > > a (
|
|
in_place,
|
|
#if 0
|
|
in_place,
|
|
#else
|
|
// nonstd_lite_in_place_type_t(int),
|
|
static_cast< nonstd::in_place_t >( in_place ),
|
|
#endif
|
|
nullopt
|
|
);
|
|
|
|
EXPECT( a );
|
|
EXPECT( *a );
|
|
EXPECT_NOT( **a );
|
|
#endif
|
|
}
|
|
// end of file
|