expect.hpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //
  2. // require.hpp
  3. // gameutils
  4. //
  5. // Created by Sam Jaffe on 8/19/16.
  6. //
  7. #pragma once
  8. #include <stdexcept>
  9. #undef CONCAT2
  10. #define CONCAT2(A, B) A##B
  11. #undef CONCAT
  12. #define CONCAT(A, B) CONCAT2(A, B)
  13. #undef STRING2
  14. #define STRING2(A) #A
  15. #undef STRING
  16. #define STRING(A) STRING2(A)
  17. #undef GET_MACRO_3
  18. #define GET_MACRO_3(_1,_2,_3,NAME,...) NAME
  19. namespace contract {
  20. template <typename except>
  21. void _contract_impl(bool expr, std::string const & msg, char const * = "") {
  22. if ( ! expr ) throw except{ msg };
  23. }
  24. template <typename except>
  25. void _contract_impl(bool expr, char const * msg, char const * = "") {
  26. if ( ! expr ) throw except{ msg };
  27. }
  28. }
  29. #define FIRST_ELEMENT( X, ... ) X
  30. #define SECOND_ELEMENT( X, Y, ... ) Y
  31. #define exception_type( ... ) GET_MACRO_3( __VA_ARGS__, SECOND_ELEMENT, FIRST_ELEMENT, FIRST_ELEMENT )( __VA_ARGS__ )
  32. #define IGNORE( ... )
  33. #define COMMA_FIRST_ELEMENT( X, ... ) , X
  34. #define COMMA_SECOND_ELEMENT( X, Y, ... ) , Y
  35. #define pop_exception( ... ) GET_MACRO_3( "", ##__VA_ARGS__, COMMA_SECOND_ELEMENT, COMMA_FIRST_ELEMENT, IGNORE )( __VA_ARGS__ )
  36. #if defined( __clang__ ) || defined( __GNUC__ )
  37. # define FUNCTION STRING(__PRETTY_FUNCTION__)
  38. #elif defined( _MSC_VER )
  39. # define FUNCTION STRING(__FUNCTION__)
  40. #else
  41. # define FUNCTION "???"
  42. #endif
  43. #define get_default_message( header, expr ) \
  44. header #expr ". in " FUNCTION "(" __FILE__ ":" STRING( __LINE__ ) ")"
  45. #define expects( expr, ... ) \
  46. contract::_contract_impl< exception_type( std::logic_error, ##__VA_ARGS__ ) >( \
  47. expr pop_exception( __VA_ARGS__ ), \
  48. get_default_message( "precondition failed: ", expr ) )
  49. #if ! defined( EXPECT_USE_ENSURE_AUTORETURN_BEHAVIOR )
  50. #define ensures( cond, ... ) \
  51. contract::_contract_impl< exception_type( std::runtime_error, ##__VA_ARGS__ )>( \
  52. cond , ##__VA_ARGS__ , \
  53. get_default_message( "postcondition failed: ", cond ) )
  54. #else
  55. /**
  56. * RVO works if expr is an rvalue, but not if it is an
  57. * lvalue. e.g:
  58. * return ensures( expression, condition );
  59. * will rvo the object (if expression is rvo-able)
  60. * but
  61. * return ensures( var, condition );
  62. * will not, instead copies
  63. * By making _ an argument, both options will move
  64. */
  65. #define ensures( expr, cond, ... ) \
  66. [ & ]( ) { \
  67. decltype((expr)) _ = expr; \
  68. contract::_contract_impl< exception_type( std::runtime_error, ##__VA_ARGS__ ) >( \
  69. cond , ##__VA_ARGS__ , \
  70. get_default_message( "postcondition failed: ", cond ) ); \
  71. return _; \
  72. }( )
  73. #endif