Euphoria
assert.cc
Go to the documentation of this file.
1 #include "assert/assert.h"
2 
3 #ifdef IMPLEMENT_ASSERT_LIB
4 
5 #include <iostream>
6 
7 #ifndef _MSC_VER
8 #include <cxxabi.h>
9 #include <execinfo.h>
10 #endif
11 
12 #include <memory>
13 #include <vector>
14 #include <sstream>
15 
16 namespace eu
17 {
18 #ifdef _MSC_VER
19  // todo(Gustav): implement backtrace for windows?
20  namespace
21  {
22  std::vector<std::string>
23  run_backtrace(int)
24  {
25  return {};
26  }
27  }
28 
29 #else
30  namespace
31  {
32  // backtrace code stolen from:
33  // http://stackoverflow.com/questions/19190273/how-to-print-call-stack-in-c-c-more-beautifully
34 
35  std::string
36  demangle_symbol(const char* const symbol)
37  {
38  const std::unique_ptr<char, decltype(&std::free)> demangled
39  (
40  abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr),
41  &std::free
42  );
43  if(demangled)
44  {
45  return demangled.get();
46  }
47 
48  return symbol;
49  }
50 
51  std::vector<std::string>
52  run_backtrace(int skip)
53  {
54  // todo replace hardcoded limit?
55  void* addresses[256];
56  const int n = ::backtrace
57  (
58  static_cast<void**>(addresses),
59  std::extent<decltype(addresses)>::value
60  );
61  const std::unique_ptr<char*, decltype(&std::free)> symbols
62  (
63  ::backtrace_symbols(static_cast<void* const*>(addresses), n),
64  &std::free
65  );
66 
67  std::vector<std::string> ret;
68  for(int backtrace_index = skip; backtrace_index < n; backtrace_index += 1)
69  {
70  // we parse the symbols retrieved from backtrace_symbols() to
71  // extract the "real" symbols that represent the mangled names.
72  char* const symbol = symbols.get()[backtrace_index];
73  char* end = symbol;
74  while(*end != 0)
75  {
76  ++end;
77  }
78  // scanning is done backwards, since the module name
79  // might contain both '+' or '(' characters.
80  while(end != symbol && *end != '+')
81  {
82  --end;
83  }
84  char* begin = end;
85  while(begin != symbol && *begin != '(')
86  {
87  --begin;
88  }
89 
90  if(begin != symbol)
91  {
92  const auto first_symbol = std::string(symbol, ++begin - symbol);
93  *end++ = '\0';
94  const auto second_symbol = demangle_symbol(begin);
95  ret.emplace_back(fmt::format("{}{}+{}", first_symbol, second_symbol, end));
96  }
97  else
98  {
99  ret.emplace_back(symbol);
100  }
101  }
102 
103  return ret;
104  }
105  }
106 #endif
107 
108 }
109 
110 template <> struct fmt::formatter<eu::assertlib::AssertArgumentValue> : formatter<std::string>
111 {
112  template <typename FormatContext>
113  auto format(const eu::assertlib::AssertArgumentValue& c, FormatContext& ctx) const
114  {
115  return formatter<string_view>::format(c.value, ctx);
116  }
117 };
118 
119 namespace eu::assertlib
120 {
121  bool&
122  should_throw_variable()
123  {
124  static bool should_throw = false;
125  return should_throw;
126  }
127 
128  void
130  {
131  should_throw_variable() = true;
132  }
133 
134  bool
135  is_throwing()
136  {
137  return should_throw_variable();
138  }
139 
140  void
141  on_assert
142  (
143  const char* const expression,
144  int line,
145  const char* const file,
146  const char* const argstr,
147  const std::vector<AssertArgumentValue>& arguments,
148  const char* function
149  )
150  {
151  const auto start = fmt::format(
152  "Assertion failed: {}\n"
153  "Function: {}\n"
154  "File: {}:{}\n", expression, function, file, line);
155 
156  const auto with_arguments = arguments.empty()
157  ? start
158  : fmt::format("{}({}) = {}\n", start, argstr, fmt::join(arguments, ", "))
159  ;
160 
161  const auto trace = run_backtrace(2);
162  const auto message = trace.empty()
163  ? with_arguments
164  : fmt::format("{}Backtrace:\n{}\n", with_arguments, fmt::join(trace, "\n"))
165  ;
166 
167  if(should_throw_variable())
168  {
169  throw std::move(message);
170  }
171  else
172  {
173  std::cerr << message;
174  exit(-1);
175  }
176  }
177 }
178 
179 
180 #endif
bool is_throwing()
void begin_throwing()
void on_assert(const char *expression, int line, const char *file, const char *argstr, const std::vector< AssertArgumentValue > &arguments, const char *function)
DirPath join(const DirPath &lhs, const DirPath &rhs)
Definition: vfs_path.cc:419
Definition: assert.h:90
int line
Definition: nlp_sentence.cc:91