eswitch-v5
Advanced counterpart for switch statement in C++
Examples

Matching


Default case match

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
int main()
{
using namespace eswitch_v5;
const Place p = las_vegas;
bool executed = false;
eswitch( p )
(
Case( california ) { assert( false ); },
Case( washington ) { assert( false ); },
Case( new_york ) { assert( false ); },
Case( new_jersey ) { assert( false ); },
Default { executed = true; }
);
assert( executed );
}

Match by multiple parameters

#include <cassert>
#include <memory>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
class Parser{/*code*/};
int main()
{
using namespace eswitch_v5;
{
std::unique_ptr< Parser > parser( new Parser{} );
const Place p = california;
bool executed = false;
eswitch( p, parser )
(
Case( _1 == california && _2 == nullptr ) { assert( false ); },
Case( _1 == california && _2 != nullptr ) { executed = true; }
);
assert( executed );
}
{
std::unique_ptr< Parser > parser( new Parser{} );
const Place p = california;
bool executed = false;
eswitch( p, parser )
(
Case( _1 == california || _2 == nullptr ) { executed = true; },
Case( _1 == california && _2 != nullptr ) { assert( false ); }
);
assert( executed );
}
}

Out of order match

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
int main()
{
using namespace eswitch_v5;
const Place p1 = california;
const Place p2 = washington;
const Place p3 = new_york;
{
bool executed = true;
eswitch( p1, p2, p3 )
(
Case( _1 == california && _3 == new_york && _2 == washington ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
{
bool executed = true;
eswitch( p1, p2, p3 )
(
Case( _3 == new_york && _1 == california && _2 == washington ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
{
bool executed = true;
eswitch( p1, p2, p3 )
(
Case( _3 == new_york && _2 == washington && _1 == california ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
}

Partial match

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
int main()
{
using namespace eswitch_v5;
const Place p1 = california;
const Place p2 = washington;
const Place p3 = new_york;
auto status = eswitch( p1, p2, p3 )
(
Case( _3 == new_york ) { return true; },
Case( _1 == california && _3 == new_york ) { return false; },
Case( _2 == washington && _3 == new_york ) { return false; },
Case( _1 == california && _2 == washington ) { return false; },
Case( _1 == california && _2 == washington && _3 == new_york ){ return false; },
Default { assert( false ); return false; }
);
assert( status );
}

Mixed conditions

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
bool is_positive( const int i ) { return i > 0; }
bool is_odd( const int i ) { return i % 2 != 0; }
int main()
{
using namespace eswitch_v5;
bool executed = false;
eswitch( 7 )
(
Case( _1 != 0 && ( is_positive, _1 ) && ( is_odd, _1 ) ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}

Individual entries


Match for std::pair

#include <cassert>
#include <string>
#include <eswitch_v5.hpp>
int main()
{
using namespace eswitch_v5;
using namespace std::string_literals;
auto pr = std::make_pair( 10, "H"s );
{ // match
auto result = eswitch( pr )
(
Case( 10, "H" ) { return true; },
Default { return false; }
);
assert( result );
}
{ // partial-match
auto result = eswitch( pr )
(
Case( _2 == "Hello" ) { return true; },
Default { return false; }
);
assert( !result );
}
{ // no-match
auto result = eswitch( pr )
(
Case( 10, "Hello" ) { return true; },
Default { return false; }
);
assert( !result );
}
}

Match for std::tuple

#include <cassert>
#include <string>
#include <eswitch_v5.hpp>
int main()
{
using namespace eswitch_v5;
auto tup = std::make_tuple( 1, 0, 0, 1 );
{ // match
auto result = eswitch( tup )
(
Case( 1, 0, 0, 1 ) { return 9; },
Case( 1, 1, 1, 1 ) { return 15; },
Default { return -1; }
);
assert( result == 9 );
}
{ // partial-match
auto result = eswitch( tup )
(
Case( _2 == 0 && _3 == 0 ) { return true; },
Default { return false; }
);
assert( result );
}
{ // no-match
auto result = eswitch( tup )
(
Case( 1, 1, 0, 1 ) { return 13; },
Case( 1, 1, 1, 1 ) { return 15; },
Default { return -1; }
);
assert( result == -1 );
}
}

Predicates


Free function predicate

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
bool is_nonzero( const int i ) { return i != 0; }
bool is_positive( const int i, const int j ) { return i > 0 && j > 0; }
int main()
{
using namespace eswitch_v5;
{
bool executed = false;
eswitch( 0, 1 )
(
Case( ( is_nonzero, _1 ) || ( is_nonzero, _2 ) ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
{
bool executed = false;
eswitch( 1, 2 )
(
Case( ( is_positive, _1, _2 ) ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
}

Lambda predicate

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
int main()
{
using namespace eswitch_v5;
auto is_nonzero = []( const int i ) { return i != 0; };
{
bool executed = false;
eswitch( 1 )
(
Case( ( is_nonzero, _1 ) ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
{
bool executed = false;
eswitch( 0, 1 )
(
Case( ( is_nonzero, _1 ) || ( is_nonzero, _2 ) ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
auto is_positive = []( const int i, const int j ) { return i > 0 && j > 0; };
{
bool executed = false;
eswitch( 1, 2 )
(
Case( ( is_positive, _1, _2 ) ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
}

Regex


Just match

#include <cassert>
#include <string>
#include <eswitch_v5.hpp>
int main()
{
using namespace eswitch_v5;
using namespace std::string_literals;
const auto phone_number = "^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\\s\\./0-9]*$"_r;
const auto email = "[\\w-]+@([\\w-]+\\.)+[\\w-]+"_r;
{
bool executed = false;
eswitch( "joe@aol.com"s )
(
Case( phone_number ) { assert( false ); },
Case( email ) { executed = true; }
);
assert( executed );
}
{
bool executed = false;
eswitch( "+(123)-456-78-90"s )
(
Case( phone_number ) { executed = true; },
Case( email ) { assert( false ); }
);
assert( executed );
}
}

Match and withdraw

#include <cassert>
#include <map>
#include <eswitch_v5.hpp>
std::vector< std::string > get_tokenized_http_response()
{
{
{ "HTTP/1.1 200 OK" },
{ "Content-Lenght: 88" },
{ "Content-Type: text/html" }
};
return v;
}
int main()
{
using namespace eswitch_v5;
using namespace std::string_literals;
for( const auto & line : get_tokenized_http_response() )
{
const bool to_continue =
eswitch( line )
(
Case( "^.+ 200 .+$"_r ) { return true; },
Case( "^(.+): (.+)$"_r )( const std::vector< std::string > & match ){
fields[ match[ 1 ] ] = match[ 2 ];
return true;
},
Default { return false; }
);
if( !to_continue ) break;
}
assert( fields.size() == 2 );
assert( fields[ "Content-Lenght"s ] == "88"s );
assert( fields[ "Content-Type"s ] == "text/html"s );
}

Withdrawing underlying value


Match for std::any

#include <cassert>
#include <any>
#include <eswitch_v5.hpp>
int main()
{
using namespace eswitch_v5;
{ // match
std::any a = 888;
auto result = eswitch( a )
(
Case( is<float>{} ) ( float f )
{
return f;
},
Case( is<int>{} ) ( int i )
{
return i;
},
Default { return -1; }
);
assert( result == 888 );
}
{ // no-match
std::any a = std::string{"Hello"};
auto result = eswitch( a )
(
Case( is<float>{} ) ( float f )
{
return f;
},
Case( is<int>{} ) ( int i )
{
return i;
},
Default { return -1; }
);
assert( result == -1 );
}
}

Match for std::variant<...>

#include <cassert>
#include <variant>
#include <eswitch_v5.hpp>
int main()
{
using namespace eswitch_v5;
auto result = eswitch( var )
(
Case( is<std::string>{} ) ( const std::string & str )
{
return str.size();
},
Case( is<int>{} ) ( int i )
{
return i;
},
Default { return -1; }
);
assert( result == 5 );
}

Match for polymorphic types

#include <cassert>
#include <eswitch_v5.hpp>
struct base
{
virtual ~base() = default;
virtual int area() = 0;
};
struct circle : base{ int area() { return 10; } };
struct square : base{ int area() { return 20; } };
int main()
{
using namespace eswitch_v5;
circle c;
base & b = c;
auto result = eswitch( b )
(
Case( is<circle>{} )( circle & c )
{
return c.area();
},
Case( is<square>{} )( square & s )
{
return s.area();
},
Default { return -1; }
);
assert( result == 10 );
}

Falling properties


Explicit fallthrough

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
int main()
{
using namespace eswitch_v5;
Place p = california;
{
bool executed_1st_case = false;
bool executed_2nd_case = false;
eswitch( p )
(
Case( california ) { executed_1st_case = true; } ^ fallthrough_,
Case( new_york ) { executed_2nd_case = true; },
Default { assert( false ); }
);
assert( executed_1st_case && executed_2nd_case );
}
{
bool executed_1st_case = false;
bool executed_2nd_case = false;
bool executed_default_case = false;
eswitch( p )
(
Case( california ) { executed_1st_case = true; } ^ fallthrough_,
Case( new_york ) { executed_2nd_case = true; } ^ fallthrough_,
Default { executed_default_case = true; }
);
assert( executed_1st_case && executed_2nd_case && executed_default_case );
}
}

Implicit break

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
int main()
{
using namespace eswitch_v5;
Place p = california;
eswitch( p )
(
Case( _1 == california ) {},
Case( _1 == california ) { assert( false ); },
Default { assert( false ); }
);
}

Utilities


any_from

#include <cassert>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
int main()
{
using namespace eswitch_v5;
for( const auto p : { california, washington, new_york } )
{
bool executed = false;
eswitch( p )
(
Case( _1 == any_from( california, washington, new_york ) ) { executed = true; },
Default { assert( false ); }
);
assert( executed );
}
}

Stringification


Enum to string

#include <cassert>
#include <string>
#include <eswitch_v5.hpp>
enum Place{ california, washington, new_york, new_jersey, las_vegas };
const char * to_string( const Place p )
{
using namespace eswitch_v5;
return eswitch( p )
(
Case( california ) { return "california"; },
Case( washington ) { return "washington"; },
Case( new_york ) { return "new_york"; },
Case( new_jersey ) { return "new_jersey"; },
Case( las_vegas ) { return "las_vegas"; },
Default { return "unknown"; }
);
}
int main()
{
const std::string actualResult[] = { "california", "washington", "new_york", "new_jersey", "las_vegas" };
for( const auto p : { california, washington, new_york, new_jersey, las_vegas } )
{
assert( std::string{ to_string( p ) } == actualResult[ static_cast< int >( p ) ] );
}
}

Customization


Floating point comparison

#include <cassert>
#include <cmath>
#include <eswitch_v5.hpp>
struct double_value
{
double value;
};
bool operator==( const double d, const double_value f )
{
return fabs( d - f.value ) < __FLT_EPSILON__;
}
double_value operator""_dbl( const long double f )
{
return { static_cast< double >( f ) };
}
int main()
{
using namespace eswitch_v5;
eswitch( 2 - 0.7000000001 )
(
Case( 1.3_dbl ) {},
Default { assert( false ); }
);
}

Value and Type transferring

#include <cassert>
#include <cmath>
#include <eswitch_v5.hpp>
template< typename T >
struct Holder{};
// Intermediate structures which is needed for compiler 'name lookup'.
struct Has_value{};
struct Has_type {};
// - eswitch_v5::NoneIndex is mandatory here, since I have another
// overload of 'operator==' internally and because of it compiler
// choose wrong implementation. Thus using concept 'eswitch_v5::NoneIndex'
// prevent compiler from choosing wrong implementation.
// - Second argument must be 'const', since internally I keep it
// as const reference( because it shouldn't be mutable ) and
// avoiding using 'const' will lead to the situation where
// compiler won't be able to match for this overload.
template< eswitch_v5::NoneIndex T >
auto operator==( T&&, const Has_value )
{
using T_ = std::decay_t< T >;
if constexpr( requires{ T_::value; } )
return std::make_optional( T_::value );
else
return false;
}
template< eswitch_v5::NoneIndex T >
auto operator==( T&&, const Has_type )
{
using T_ = std::decay_t< T >;
if constexpr( requires{ typename T_::type; } )
return std::make_optional( Holder< typename T_::type >{} );
else
return false;
}
int main()
{
using namespace eswitch_v5;
(
Case( Has_value{} )( int transferred_value )
{
return transferred_value;
},
Case( Has_type{} )( Holder< int > transferred_type )
{
return sizeof( int );
},
Default { return 0; }
);
assert( r == sizeof( int ) );
}
std::make_tuple
T make_tuple(T... args)
eswitch_v5::_1
constexpr Index_< 0 > _1
Definition: eswitch_v5.hpp:174
std::string
STL class.
std::fabs
T fabs(T... args)
std::vector
STL class.
std::map::size
T size(T... args)
std::make_optional
T make_optional(T... args)
eswitch_v5::fallthrough_
static constexpr Fallthrough fallthrough_
Indicates fall through from previous Case without testing condition of following Case.
Definition: eswitch_v5.hpp:1016
eswitch_v5::_3
constexpr Index_< 2 > _3
Definition: eswitch_v5.hpp:176
any
cmath
eswitch_v5::is
Used to match for type of active entry in std::any, std::variant<...> and polymorphic types.
Definition: eswitch_v5.hpp:60
eswitch_v5::any_from
static constexpr auto any_from(Args &&... args)
Helper function which allows to find if something is within the list( passed arguments ).
Definition: eswitch_v5.hpp:991
std::to_string
T to_string(T... args)
map
memory
std::experimental::filesystem::status
T status(T... args)
std::decay_t
Default
#define Default
Declares body which will be executed in case of no other matches.
Definition: eswitch_v5.hpp:1029
cassert
Case
#define Case(...)
Accepts conditions of various forms.
Definition: eswitch_v5.hpp:1026
eswitch_v5::eswitch
static constexpr auto eswitch(Ts &&... ts)
This function is responsible for passing arguments for class eswitch_impl with overloaded operator(),...
Definition: eswitch_v5.hpp:838
std::make_pair
T make_pair(T... args)
eswitch_v5::operator==
static auto operator==(const std::string &tuple_entry, const regexter &value)
CaseModule to support for matching and withdrawing of values for and from regular expression.
Definition: eswitch_v5.hpp:413
std::unique_ptr
STL class.
eswitch_v5
Definition: eswitch_v5.hpp:27
eswitch_v5.hpp
implementation which enhance switch statement
eswitch_v5::_2
constexpr Index_< 1 > _2
Definition: eswitch_v5.hpp:175
variant
string