Browse Source

Fixing for non-GCC compiler

Sam Jaffe 8 years ago
parent
commit
f88db5706b
1 changed files with 44 additions and 29 deletions
  1. 44 29
      expect.hpp

+ 44 - 29
expect.hpp

@@ -19,8 +19,13 @@
 #undef STRING
 #define STRING(A) STRING2(A)
 
-#undef GET_MACRO_3
-#define GET_MACRO_3(_1,_2,_3,NAME,...) NAME
+/* 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>
@@ -34,17 +39,21 @@ namespace contract {
   }
 }
 
-#define  FIRST_ELEMENT( X, ... ) X
-#define SECOND_ELEMENT( X, Y, ... ) Y
+#define EXCEPT_T_TWO(X, Y) Y
+#define EXCEPT_T_THREE(X, Y, Z) Z
+#define EXCEPT_T_FOURPLUS(X, Y, Z, ...) Z
 
-#define exception_type( ... ) GET_MACRO_3( __VA_ARGS__, SECOND_ELEMENT, FIRST_ELEMENT, FIRST_ELEMENT )( __VA_ARGS__ )
+#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 IGNORE( ... )
+#define EXCEPT_MSG_TWO(X, Y) Y
+#define EXCEPT_MSG_THREE(X, Y, Z) Y
+#define EXCEPT_MSG_FOURPLUS(X, Y, Z, ...) Y
 
-#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__ )
+#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__)
@@ -54,11 +63,11 @@ namespace contract {
 # define FUNCTION "???"
 #endif
 
-#define get_default_message( header, expr ) \
-  header #expr ". in " FUNCTION "(" __FILE__ ":" STRING( __LINE__ ) ")"
+#define DEF_MSG( header, expr ) \
+  header " failed: " STRING(expr) ". in " FUNCTION "(" __FILE__ ":" STRING( __LINE__ ) ")"
 
-#define get_subs_message( header, bool_expr, rval_expr ) \
-  header #bool_expr " [ with _ = " #rval_expr " ]. in " FUNCTION "(" __FILE__ ":" STRING( __LINE__ ) ")"
+#define SUB_MSG( header, bool_expr, rval_expr ) \
+  header " failed: " STRING(bool_expr) " [ with _ = " STRING(rval_expr) " ]. in " FUNCTION "(" __FILE__ ":" STRING( __LINE__ ) ")"
 
 /*
  * Usage: 
@@ -66,10 +75,12 @@ namespace contract {
  *  expects( bool-expr, custom_msg )
  *  expects( bool-expr, error_type, custom_msg )
  */
-#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 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:
@@ -87,10 +98,12 @@ namespace contract {
  *  ensures( bool-expr, custom_msg )
  *  ensures( bool-expr, error_type, custom_msg )
  */
-#define ensures( cond, ... ) \
-  contract::_contract_impl< exception_type( std::runtime_error, ##__VA_ARGS__ )>( \
-    cond pop_exception( __VA_ARGS__ ) , \
-    get_default_message( "postcondition failed: ", cond ) )
+#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__))) \
+  )
 
 
 /**
@@ -113,20 +126,22 @@ namespace contract {
  *  ensure-expr - A special boolean expression using the token '_'.
  */
 #if __cplusplus < 201300
-#define return_ensures( expr, cond, ... ) \
+#define return_ensures( expr, ... ) \
   [ & ]( ) { \
     decltype((expr)) _ = expr; \
-    contract::_contract_impl< exception_type( std::runtime_error, ##__VA_ARGS__ ) >( \
-        cond pop_exception( __VA_ARGS__ ) , \
-        get_subs_message( "postcondition failed: ", cond, 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< exception_type( std::runtime_error, ##__VA_ARGS__ ) >( \
-        cond pop_exception( __VA_ARGS__ ) , \
-        get_subs_message( "postcondition failed: ", cond, 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 _; \
   }( )
 #endif