// // require.hpp // gameutils // // Created by Sam Jaffe on 8/19/16. // #pragma once #include #undef CONCAT2 #define CONCAT2(A, B) A##B #undef CONCAT #define CONCAT(A, B) CONCAT2(A, B) #undef STRING2 #define STRING2(A) #A #undef STRING #define STRING(A) STRING2(A) #undef GET_MACRO_3 #define GET_MACRO_3(_1,_2,_3,NAME,...) NAME namespace contract { template void _contract_impl(bool expr, std::string const & msg, char const * = "") { if ( ! expr ) throw except{ msg }; } template void _contract_impl(bool expr, char const * msg, char const * = "") { if ( ! expr ) throw except{ msg }; } } #define FIRST_ELEMENT( X, ... ) X #define SECOND_ELEMENT( X, Y, ... ) Y #define exception_type( ... ) GET_MACRO_3( __VA_ARGS__, SECOND_ELEMENT, FIRST_ELEMENT, FIRST_ELEMENT )( __VA_ARGS__ ) #define IGNORE( ... ) #define COMMA_FIRST_ELEMENT( X, ... ) , X #define COMMA_SECOND_ELEMENT( X, Y, ... ) , Y #define pop_exception( ... ) GET_MACRO_3( "", ##__VA_ARGS__, COMMA_SECOND_ELEMENT, COMMA_FIRST_ELEMENT, IGNORE )( __VA_ARGS__ ) #if defined( __clang__ ) || defined( __GNUC__ ) # define FUNCTION STRING(__PRETTY_FUNCTION__) #elif defined( _MSC_VER ) # define FUNCTION STRING(__FUNCTION__) #else # define FUNCTION "???" #endif #define get_default_message( header, expr ) \ header #expr ". in " FUNCTION "(" __FILE__ ":" STRING( __LINE__ ) ")" #define expects( expr, ... ) \ contract::_contract_impl< exception_type( std::logic_error, ##__VA_ARGS__ ) >( \ expr pop_exception( __VA_ARGS__ ), \ get_default_message( "precondition failed: ", expr ) ) /* #define ensures( cond, ... ) \ contract::_contract_impl< exception_type( std::runtime_error, ##__VA_ARGS__ )>( \ cond , ##__VA_ARGS__ , \ get_default_message( "postcondition failed: ", cond ) ) */ /** * RVO works if expr is an rvalue, but not if it is an * lvalue. e.g: * return ensures( expression, condition ); * will rvo the object (if expression is rvo-able) * but * return ensures( var, condition ); * will not, instead copies * By making _ an argument, both options will move */ #define ensures( expr, cond, ... ) \ [ & ]( ) { \ decltype((expr)) _ = expr; \ contract::_contract_impl< exception_type( std::runtime_error, ##__VA_ARGS__ ) >( \ cond , ##__VA_ARGS__ , \ get_default_message( "postcondition failed: ", cond ) ); \ return _; \ }( )