rapidyaml  0.11.1
parse and emit YAML, and do it fast
common.cpp
Go to the documentation of this file.
1 #include "c4/yml/common.hpp"
2 #include "c4/yml/error.hpp"
3 #include "c4/yml/error.def.hpp"
4 
5 #ifndef RYML_NO_DEFAULT_CALLBACKS
6 # include <stdlib.h>
7 # include <stdio.h>
8 #endif // RYML_NO_DEFAULT_CALLBACKS
9 #ifdef _RYML_EXCEPTIONS
10 # include <stdexcept>
11 #endif
12 
13 
14 namespace c4 {
15 namespace yml {
16 
17 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
18 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702/*unreachable code*/) // on the call to the unreachable macro
19 
20 namespace {
21 Callbacks s_default_callbacks;
22 
23 #ifndef RYML_NO_DEFAULT_CALLBACKS
24 
25 C4_NO_INLINE void dump2stderr(csubstr s)
26 {
27  // using fwrite() is more portable than using fprintf("%.*s") which
28  // is not available in some embedded platforms
29  if(s.len)
30  fwrite(s.str, 1, s.len, stderr); // NOLINT
31 }
32 C4_NO_INLINE void endmsg()
33 {
34  fputc('\n', stderr); // NOLINT
35  fflush(stderr); // NOLINT
36 }
37 
38 [[noreturn]] C4_NO_INLINE void error_basic_impl(csubstr msg, ErrorDataBasic const& errdata, void * /*user_data*/)
39 {
40  err_basic_format(dump2stderr, msg, errdata);
41  endmsg();
42  #ifdef _RYML_WITH_EXCEPTIONS
43  throw ExceptionBasic(msg, errdata);
44  #else
45  abort(); // LCOV_EXCL_LINE
46  #endif
47 }
48 
49 [[noreturn]] C4_NO_INLINE void error_parse_impl(csubstr msg, ErrorDataParse const& errdata, void * /*user_data*/)
50 {
51  err_parse_format(dump2stderr, msg, errdata);
52  endmsg();
53  #ifdef _RYML_WITH_EXCEPTIONS
54  throw ExceptionParse(msg, errdata);
55  #else
56  abort(); // LCOV_EXCL_LINE
57  #endif
58 }
59 
60 [[noreturn]] C4_NO_INLINE void error_visit_impl(csubstr msg, ErrorDataVisit const& errdata, void * /*user_data*/)
61 {
62  err_visit_format(dump2stderr, msg, errdata);
63  endmsg();
64  #ifdef _RYML_WITH_EXCEPTIONS
65  throw ExceptionVisit(msg, errdata);
66  #else
67  abort(); // LCOV_EXCL_LINE
68  #endif
69 }
70 
71 void* allocate_impl(size_t length, void * /*hint*/, void * /*user_data*/)
72 {
73  void *mem = ::malloc(length);
74  if(mem == nullptr)
75  error_basic_impl("could not allocate memory", ErrorDataBasic{RYML_LOC_HERE()}, nullptr); // LCOV_EXCL_LINE
76  return mem;
77 }
78 
79 void free_impl(void *mem, size_t /*length*/, void * /*user_data*/)
80 {
81  ::free(mem);
82 }
83 
84 #endif // RYML_NO_DEFAULT_CALLBACKS
85 
86 } // anon namespace
87 
88 
89 void set_callbacks(Callbacks const& c)
90 {
91  s_default_callbacks = c;
92 }
93 
95 {
96  return s_default_callbacks;
97 }
98 
100 {
102 }
103 
104 
106  :
107  m_user_data(nullptr),
108  #ifndef RYML_NO_DEFAULT_CALLBACKS
109  m_allocate(allocate_impl),
110  m_free(free_impl),
111  m_error_basic(error_basic_impl),
112  m_error_parse(error_parse_impl),
113  m_error_visit(error_visit_impl)
114  #else
115  m_allocate(nullptr),
116  m_free(nullptr),
117  m_error_basic(nullptr),
118  m_error_parse(nullptr),
119  m_error_visit(nullptr)
120  #endif
121 {
122 }
123 
124 Callbacks::Callbacks(void *user_data, pfn_allocate alloc_, pfn_free free_, pfn_error_basic error_basic_)
125  :
126  m_user_data(user_data),
128  m_allocate(alloc_ ? alloc_ : allocate_impl),
129  m_free(free_ ? free_ : free_impl),
130  m_error_basic(error_basic_ ? error_basic_ : error_basic_impl),
131  m_error_parse(error_parse_impl),
132  m_error_visit(error_visit_impl)
133  #else
134  m_allocate(alloc_),
135  m_free(free_),
136  m_error_basic(error_basic_),
137  m_error_parse(nullptr),
138  m_error_visit(nullptr)
139  #endif
140 {
141 }
142 
143 
145 {
146  m_user_data = user_data;
147  return *this;
148 }
149 
151 {
152  m_allocate = allocate;
153  #ifndef RYML_NO_DEFAULT_CALLBACKS
154  m_allocate = m_allocate ? m_allocate : allocate_impl;
155  #endif
156  return *this;
157 }
158 
160 {
161  m_free = free;
162  #ifndef RYML_NO_DEFAULT_CALLBACKS
163  m_free = m_free ? m_free : free_impl;
164  #endif
165  return *this;
166 }
167 
169 {
170  m_error_basic = error_basic;
171  #ifndef RYML_NO_DEFAULT_CALLBACKS
172  m_error_basic = m_error_basic ? m_error_basic : error_basic_impl;
173  #endif
174  return *this;
175 }
176 
178 {
179  m_error_parse = error_parse;
180  #ifndef RYML_NO_DEFAULT_CALLBACKS
181  m_error_parse = m_error_parse ? m_error_parse : error_parse_impl;
182  #endif
183  return *this;
184 }
185 
187 {
188  m_error_visit = error_visit;
189  #ifndef RYML_NO_DEFAULT_CALLBACKS
190  m_error_visit = m_error_visit ? m_error_visit : error_visit_impl;
191  #endif
192  return *this;
193 }
194 
195 
196 C4_NORETURN C4_NO_INLINE void err_basic(ErrorDataBasic const& errdata, const char* msg)
197 {
198  err_basic(get_callbacks(), errdata, msg);
199  C4_UNREACHABLE_AFTER_ERR();
200 }
201 C4_NORETURN C4_NO_INLINE void err_basic(Callbacks const& callbacks, ErrorDataBasic const& errdata, const char* msg_)
202 {
203  csubstr msg = to_csubstr(msg_);
204  callbacks.m_error_basic(msg, errdata, callbacks.m_user_data);
205  abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
206  C4_UNREACHABLE_AFTER_ERR();
207 }
208 
209 
210 C4_NORETURN C4_NO_INLINE void err_parse(ErrorDataParse const& errdata, const char *msg)
211 {
212  err_parse(get_callbacks(), errdata, msg);
213  C4_UNREACHABLE_AFTER_ERR();
214 }
215 C4_NORETURN C4_NO_INLINE void err_parse(Callbacks const& callbacks, ErrorDataParse const& errdata, const char *msg_)
216 {
217  csubstr msg = to_csubstr(msg_);
218  if(callbacks.m_error_parse)
219  callbacks.m_error_parse(msg, errdata, callbacks.m_user_data);
220  // fall to basic error if there is no parse handler set
221  else if(callbacks.m_error_basic)
222  callbacks.m_error_basic(msg, errdata.ymlloc, callbacks.m_user_data);
223  abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
224  C4_UNREACHABLE_AFTER_ERR();
225 }
226 
227 
228 C4_NORETURN C4_NO_INLINE void err_visit(ErrorDataVisit const& errdata, const char *msg)
229 {
230  err_visit(get_callbacks(), errdata, msg);
231  C4_UNREACHABLE_AFTER_ERR();
232 }
233 C4_NORETURN C4_NO_INLINE void err_visit(Callbacks const& callbacks, ErrorDataVisit const& errdata, const char *msg_)
234 {
235  csubstr msg = to_csubstr(msg_);
236  if(callbacks.m_error_visit)
237  callbacks.m_error_visit(msg, errdata, callbacks.m_user_data);
238  // fall to basic error if there is no visit handler set
239  else if(callbacks.m_error_basic)
240  callbacks.m_error_basic(msg, errdata.cpploc, callbacks.m_user_data);
241  abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
242  C4_UNREACHABLE_AFTER_ERR();
243 }
244 
245 
246 
247 #ifdef _RYML_WITH_EXCEPTIONS
248 ExceptionBasic::ExceptionBasic(csubstr msg_, ErrorDataBasic const& errdata_) noexcept
249  : errdata_basic(errdata_)
250  , msg()
251 {
252  msg[0] = '\0';
253  if(msg_.len)
254  {
255  if(msg_.len >= sizeof(msg))
256  {
257  static_assert(sizeof(msg) > 6u, "message buffer too small");
258  msg_.len = sizeof(msg) - 6u;
259  msg[msg_.len ] = '[';
260  msg[msg_.len + 1u] = '.';
261  msg[msg_.len + 2u] = '.';
262  msg[msg_.len + 3u] = '.';
263  msg[msg_.len + 4u] = ']';
264  msg[msg_.len + 5u] = '\0';
265  }
266  memcpy(msg, msg_.str, msg_.len);
267  }
268 }
269 ExceptionParse::ExceptionParse(csubstr msg_, ErrorDataParse const& errdata_) noexcept
270  : ExceptionBasic(msg_, {errdata_.ymlloc})
271  , errdata_parse(errdata_)
272 {
273 }
274 ExceptionVisit::ExceptionVisit(csubstr msg_, ErrorDataVisit const& errdata_) noexcept
275  : ExceptionBasic(msg_, {errdata_.cpploc})
276  , errdata_visit(errdata_)
277 {
278 }
279 #endif // _RYML_WITH_EXCEPTIONS
280 
281 
282 namespace detail {
283 RYML_EXPORT csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
284 {
285  if(pos > text.len)
286  return text.last(0);
287  size_t before = text.first(pos).last_of('\n');
288  size_t before_count = 0;
289  while((before != npos) && (++before_count <= num_lines_before))
290  {
291  if(before == 0)
292  break;
293  before = text.first(--before).last_of('\n');
294  }
295  if(before < text.len || before == npos)
296  ++before;
297  size_t after = text.first_of('\n', pos);
298  size_t after_count = 0;
299  while((after != npos) && (++after_count <= num_lines_after))
300  {
301  ++after;
302  if(after >= text.len)
303  break;
304  after = text.first_of('\n', after);
305  }
306  return before <= after ? text.range(before, after) : text.first(0);
307 }
308 } // namespace detail
309 
310 C4_SUPPRESS_WARNING_MSVC_POP
311 C4_SUPPRESS_WARNING_GCC_CLANG_POP
312 
313 } // namespace yml
314 } // namespace c4
Common utilities and infrastructure used by ryml.
#define RYML_NO_DEFAULT_CALLBACKS
(Undefined by default) Define this macro to disable ryml's default implementation of the callback fun...
Definition: common.hpp:183
Definitions of error utilities used by ryml.
Error utilities used by ryml.
#define RYML_EXPORT
Definition: export.hpp:15
void reset_callbacks()
set the global callbacks back to their defaults.
Definition: common.cpp:99
void set_callbacks(Callbacks const &c)
set the global callbacks for the library; after a call to this function, these callbacks will be used...
Definition: common.cpp:89
void(*)(csubstr msg, ErrorDataVisit const &errdata, void *user_data) pfn_error_visit
the type of the function used to report visit errors.
Definition: common.hpp:500
void *(*)(size_t len, void *hint, void *user_data) pfn_allocate
the type of the function used to allocate memory; ryml will only allocate memory through this callbac...
Definition: common.hpp:460
void(*)(csubstr msg, ErrorDataParse const &errdata, void *user_data) pfn_error_parse
the type of the function used to report parse errors.
Definition: common.hpp:489
Callbacks const & get_callbacks()
get the global callbacks
Definition: common.cpp:94
void(*)(csubstr msg, ErrorDataBasic const &errdata, void *user_data) pfn_error_basic
the type of the function used to report basic errors.
Definition: common.hpp:478
void(*)(void *mem, size_t size, void *user_data) pfn_free
the type of the function used to free memory; ryml will only free memory through this callback.
Definition: common.hpp:465
void err_visit(ErrorDataVisit const &errdata, const char *msg)
trigger a visit error to its respective handler, with a non-formatted error message.
Definition: common.cpp:228
void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit const &errdata)
Given an error message and associated visit error data, format it fully as a visit error message.
Definition: error.def.hpp:347
void err_basic(ErrorDataBasic const &errdata, const char *msg)
trigger a basic error to its respective handler, with a non-formatted error message.
Definition: common.cpp:196
void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic const &errdata)
Given an error message and associated basic error data, format it fully as a basic error message.
Definition: error.def.hpp:315
void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse const &errdata)
Given an error message and associated parse error data, format it fully as a parse error message.
Definition: error.def.hpp:328
void err_parse(ErrorDataParse const &errdata, const char *msg)
trigger a parse error to its respective handler, with a non-formatted error message.
Definition: common.cpp:210
csubstr to_csubstr(substr s) noexcept
neutral version for use in generic code
Definition: substr.hpp:2210
csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
Definition: common.cpp:283
@ npos
a null string position
Definition: common.hpp:258
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
A c-style callbacks class to customize behavior on errors or allocation.
Definition: common.hpp:511
pfn_error_basic m_error_basic
a pointer to a basic error handler function
Definition: common.hpp:515
pfn_error_parse m_error_parse
a pointer to a parse error handler function
Definition: common.hpp:516
Callbacks & set_error_visit(pfn_error_visit error_visit=nullptr)
Set or reset the error_visit callback.
Definition: common.cpp:186
Callbacks & set_free(pfn_free free=nullptr)
Set or reset the free callback.
Definition: common.cpp:159
void * m_user_data
data to be forwarded in every call to a callback
Definition: common.hpp:512
pfn_allocate m_allocate
a pointer to an allocate handler function
Definition: common.hpp:513
Callbacks() noexcept
Construct an object with the default callbacks.
Definition: common.cpp:105
Callbacks & set_error_parse(pfn_error_parse error_parse=nullptr)
Set or reset the error_parse callback.
Definition: common.cpp:177
Callbacks & set_allocate(pfn_allocate allocate=nullptr)
Set or reset the allocate callback.
Definition: common.cpp:150
Callbacks & set_error_basic(pfn_error_basic error_basic=nullptr)
Set or reset the error_basic callback.
Definition: common.cpp:168
pfn_error_visit m_error_visit
a pointer to a visit error handler function
Definition: common.hpp:517
pfn_free m_free
a pointer to a free handler function
Definition: common.hpp:514
Callbacks & set_user_data(void *user_data)
Set the user data.
Definition: common.cpp:144
Data for a basic error.
Definition: common.hpp:312
Data for a parse error.
Definition: common.hpp:321
Location ymlloc
location in the YAML source buffer where the error was detected.
Definition: common.hpp:323
Data for a visit error.
Definition: common.hpp:331
Location cpploc
location in the C++ source file where the error was detected.
Definition: common.hpp:332
Exception thrown by the default basic error implementation.
Definition: error.hpp:456
ExceptionBasic(csubstr msg, ErrorDataBasic const &errdata_) noexcept
Exception thrown by the default parse error implementation.
Definition: error.hpp:475
ExceptionParse(csubstr msg, ErrorDataParse const &errdata_) noexcept
Exception thrown by the default visit error implementation.
Definition: error.hpp:492
ExceptionVisit(csubstr msg, ErrorDataVisit const &errdata_) noexcept