|
|
@@ -0,0 +1,86 @@
|
|
|
+//
|
|
|
+// 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)
|
|
|
+
|
|
|
+#undef GET_MACRO_3
|
|
|
+#define GET_MACRO_3(_1,_2,_3,NAME,...) NAME
|
|
|
+
|
|
|
+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 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 _; \
|
|
|
+ }( )
|
|
|
+
|