Empirical
assert.h
Go to the documentation of this file.
1 
32 #ifndef EMP_ASSERT_H
33 #define EMP_ASSERT_H
34 
35 #include <iostream>
36 #include <string>
37 #include <sstream>
38 
39 #include "macros.h"
40 
42 
44 #ifdef EMSCRIPTEN
45 #include <emscripten.h>
46 #endif
47 
49 #ifdef NDEBUG
50 #define EMP_NDEBUG
51 #endif
52 
53 #ifdef TDEBUG
54 #define EMP_TDEBUG
55 #endif
56 
57 
59 #define emp_assert_TO_PAIR(X) EMP_STRINGIFY(X) , X
60 
62 #ifdef EMP_NDEBUG
63 namespace emp {
64  constexpr bool assert_on = false;
65 }
66 
67 // GROUP 1: --- Debug OFF ---
68 
71 #define emp_assert(...)
72 // #define emp_assert(EXPR) ((void) sizeof(EXPR) )
73 // #define emp_assert(EXPR, ...) { constexpr bool __emp_assert_tmp = false && (EXPR); (void) __emp_assert_tmp; }
74 
75 // Asserts to check only when in Emscripten should also be disabled.
76 #define emp_emscripten_assert(...)
77 
78 
79 // GROUP 2: --- Unit Testing ON ---
80 #elif defined(EMP_TDEBUG) // EMP_NDEBUG not set, but EMP_TDEBUG is!
81 
82 namespace emp {
83  constexpr bool assert_on = true;
84  struct AssertFailInfo {
85  std::string filename;
86  int line_num;
87  std::string error;
88  };
89  AssertFailInfo assert_fail_info;
90  bool assert_last_fail = false;
91 
92  template <typename... EXTRA>
93  bool assert_trigger(std::string filename, size_t line, std::string expr) {
94  emp::assert_fail_info.filename = __FILE__;
95  emp::assert_fail_info.line_num = __LINE__;
96  emp::assert_fail_info.error = expr;
97  emp::assert_last_fail = true;
98 
99  return true;
100  }
101 
102  void assert_clear() { emp::assert_last_fail = false; }
103 }
104 
105 // Unit Testing ON
106 
107 #define emp_assert(...) \
108  do { \
109  !(EMP_GET_ARG_1(__VA_ARGS__, ~)) && \
110  emp::assert_trigger(__FILE__, __LINE__, EMP_STRINGIFY( EMP_GET_ARG_1(__VA_ARGS__, ~) )); \
111  } while(0)
112 
113 // Unit-testing asserts to check only when in Emscripten should depend on if we are in Emscripten
114 #ifdef EMSCRIPTEN
115 #define emp_emscripten_assert(...) emp_assert(__VA_ARGS__)
116 #else
117 #define emp_emscripten_assert(...)
118 #endif
119 
120 
121 // GROUP 3: --- Emscripten debug ON ---
122 #elif EMSCRIPTEN // Neither EMP_NDEBUG nor EMP_TDEBUG set, but compiling with Emscripten
123 
124 namespace emp {
125  constexpr bool assert_on = true;
126  static int TripAssert() {
127  static int trip_count = 0;
128  return ++trip_count;
129  }
130 
132  void assert_print(std::stringstream &) { ; }
133 
135  template <typename T, typename... EXTRA>
136  void assert_print(std::stringstream & ss, std::string name, T && val, EXTRA &&... extra) {
137  ss << name << ": [" << val << "]" << std::endl;
138  assert_print(ss, std::forward<EXTRA>(extra)...);
139  }
140 
141  template <typename IGNORE, typename... EXTRA>
142  bool assert_trigger(std::string filename, size_t line, std::string expr, IGNORE, EXTRA &&... extra) {
143  std::stringstream ss;
144  ss << "Assert Error (In " << filename << " line " << line << "): " << expr << '\n';
145  assert_print(ss, std::forward<EXTRA>(extra)...);
146  if (emp::TripAssert() <= 3) {
147  EM_ASM_ARGS({ msg = Pointer_stringify($0); alert(msg); }, ss.str().c_str());
148  }
149 
150  // Print the current state of the stack.
151  EM_ASM( console.log('Callstack:\n' + stackTrace()); );
152  return true;
153  }
154 }
155 
156 // Debug; Emscripten ON
157 
158 #define emp_assert(...) \
159  do { \
160  !(EMP_GET_ARG_1(__VA_ARGS__, ~)) && \
161  emp::assert_trigger(__FILE__, __LINE__, EMP_WRAP_ARGS(emp_assert_TO_PAIR, __VA_ARGS__) ); \
162  } while(0)
163 
164 // Emscripten asserts should be on since we are in Emscripten
165 #define emp_emscripten_assert(...) emp_assert(__VA_ARGS__)
166 
167 
168 // GROUP 3: --- Debug ON, but Emscripten OFF ---
169 #else
170 
171 namespace emp {
172  constexpr bool assert_on = true;
173 
175  void assert_print() { ; }
176 
178  template <typename T, typename... EXTRA>
179  void assert_print(std::string name, T && val, EXTRA &&... extra) {
180  std::cerr << name << ": [" << val << "]" << std::endl;
181  assert_print(std::forward<EXTRA>(extra)...);
182  }
183 
184  template <typename IGNORE, typename... EXTRA>
185  bool assert_trigger(std::string filename, size_t line, std::string expr, IGNORE, EXTRA &&... extra) {
186  std::cerr << "Assert Error (In " << filename << " line " << line
187  << "): " << expr << std::endl;
188  assert_print(std::forward<EXTRA>(extra)...);
189  return true;
190  }
191 }
192 
194 
195 // Debug; Not Emscripten
196 
199 #define emp_assert(...) \
200  do { \
201  !(EMP_GET_ARG_1(__VA_ARGS__, ~)) && \
202  emp::assert_trigger(__FILE__, __LINE__, EMP_WRAP_ARGS(emp_assert_TO_PAIR, __VA_ARGS__) ) && \
203  (abort(), false); \
204  } while(0)
205 
206 // Emscripten-only asserts should be disabled since we are not in Emscripten
209 #define emp_emscripten_assert(...) emp_assert(__VA_ARGS__)
210 
212 
213 #endif // NDEBUG
214 
215 
216 #endif // Include guard
217 
Generally useful macros that can perform cools tricks.
static const PrintStr endl("<br>")
Pre-define emp::endl to insert a "<br>" and thus acting like a newline.
If we are in emscripten, make sure to include the header.
Definition: array.h:37