| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- //
- // require.hpp
- // gameutils
- //
- // Created by Sam Jaffe on 8/19/16.
- //
- #pragma once
- #include <stdexcept>
- #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)
- /* expands to the first argument */
- #define FIRST(...) FIRST_HELPER(__VA_ARGS__, throwaway)
- #define FIRST_HELPER(first, ...) first
- #define NUM(...) SELECT_5TH(__VA_ARGS__, FOURPLUS, THREE, TWO, ONE, throwaway)
- #define SELECT_5TH(a1, a2, a3, a4, a5, ...) a5
- namespace contract {
- template <typename except>
- void _contract_impl(bool expr, std::string const & msg, char const * = "") {
- if ( ! expr ) throw except{ msg };
- }
-
- template <typename except>
- void _contract_impl(bool expr, char const * msg, char const * = "") {
- if ( ! expr ) throw except{ msg };
- }
- }
- #define EXCEPT_T_TWO(X, Y) Y
- #define EXCEPT_T_THREE(X, Y, Z) Z
- #define EXCEPT_T_FOURPLUS(X, Y, Z, ...) Y
- #define EXCEPT_T(...) EXCEPT_T_HELPER(NUM(__VA_ARGS__), __VA_ARGS__)
- #define EXCEPT_T_HELPER(N, ...) EXCEPT_T_HELPER2(N, __VA_ARGS__)
- #define EXCEPT_T_HELPER2(N, ...) EXCEPT_T_##N(__VA_ARGS__)
- #define EXCEPT_MSG_TWO(X, Y) Y
- #define EXCEPT_MSG_THREE(X, Y, Z) Y
- #define EXCEPT_MSG_FOURPLUS(X, Y, Z, ...) Z
- #define EXCEPT_MSG(...) EXCEPT_MSG_HELPER(NUM(__VA_ARGS__), __VA_ARGS__)
- #define EXCEPT_MSG_HELPER(N, ...) EXCEPT_MSG_HELPER2(N, __VA_ARGS__)
- #define EXCEPT_MSG_HELPER2(N, ...) EXCEPT_MSG_##N(__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 LOCATION_MSG ". in " FUNCTION "(" __FILE__ ":" STRING( __LINE__ ) ")"
- #define DEF_MSG( header, expr ) \
- header " failed: " STRING(expr) LOCATION_MSG
- #define SUB_MSG( header, bool_expr, rval_expr ) \
- header " failed: " STRING(bool_expr) " [ with _ = " STRING(rval_expr) " ]" LOCATION_MSG
- /*
- * Usage:
- * expects( bool-expr )
- * expects( bool-expr, custom_msg )
- * expects( bool-expr, error_type, custom_msg )
- */
- #define expects( ... ) \
- contract::_contract_impl<EXCEPT_T( __VA_ARGS__, std::logic_error)>( \
- FIRST(__VA_ARGS__), \
- EXCEPT_MSG(__VA_ARGS__, \
- DEF_MSG("precondition", FIRST(__VA_ARGS__))) \
- )
- /*
- * Usage:
- * expects_graceful( bool-expr[, rval] )
- *
- * rval - The value to return if the expression is false.
- * Skip rval for a function returning void.
- */
- #define expects_graceful( expr, ... ) \
- if ( ! bool(expr) ) { return __VA_ARGS__; }
- /*
- * Usage:
- * ensures( bool-expr )
- * ensures( bool-expr, custom_msg )
- * ensures( bool-expr, error_type, custom_msg )
- */
- #define ensures( ... ) \
- contract::_contract_impl<EXCEPT_T(__VA_ARGS__, std::runtime_error)>( \
- FIRST(__VA_ARGS__), \
- EXCEPT_MSG(__VA_ARGS__ , \
- DEF_MSG("postcondition", FIRST(__VA_ARGS__))) \
- )
- /**
- * 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
- *
- * Usage:
- * return_ensures( rval-expr, ensure-expr )
- * return_ensures( rval-expr, ensure-expr, custom_msg )
- * return_ensures( rval-expr, ensure-expr, error_type, custom_msg )
- *
- * rval-expr - An expression that can be cast to the return type
- * of the invoking function. Bound to the token '_'.
- * ensure-expr - A special boolean expression using the token '_'.
- */
- #if __cplusplus < 201300
- #define return_ensures( expr, ... ) \
- [ & ]( ) { \
- decltype((expr)) _ = expr; \
- contract::_contract_impl<EXCEPT_T(__VA_ARGS__, std::runtime_error)>( \
- FIRST(__VA_ARGS__), \
- EXCEPT_MSG(__VA_ARGS__, \
- SUB_MSG("postcondition", FIRST(__VA_ARGS__), expr))); \
- return _; \
- }( )
- #else
- #define return_ensures( expr, cond, ... ) \
- [ _ = expr ]( ) { \
- contract::_contract_impl<EXCEPT_T(-, ##__VA_ARGS__, std::runtime_error)>( \
- cond, \
- EXCEPT_MSG(cond, ##__VA_ARGS__, \
- SUB_MSG("postcondition", cond, expr))); \
- return _; \
- }( )
- #endif
|