1 #ifndef _C4_YML_ERROR_HPP_
2 #define _C4_YML_ERROR_HPP_
6 #ifndef _C4_YML_COMMON_HPP_
11 #if (defined(C4_EXCEPTIONS) && (!defined(RYML_NO_DEFAULT_CALLBACKS) && defined(RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS))) || defined(__DOXYGEN__)
12 #define _RYML_WITH_EXCEPTIONS
14 #if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
15 # define RYML_DEBUG_BREAK() \
17 if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
23 # define RYML_DEBUG_BREAK()
27 #ifdef _RYML_WITH_EXCEPTIONS
43 _SubstrWriter(substr buf_,
size_t pos_=0) : buf(buf_), pos(pos_) { C4_ASSERT(buf.str); }
44 void append(csubstr s)
46 C4_ASSERT(!s.overlaps(buf));
47 C4_ASSERT(s.str || !s.len);
48 if(s.len && pos + s.len <= buf.len)
51 memcpy(buf.str + pos, s.str, s.len);
62 void append_n(
char c,
size_t numtimes)
65 if(numtimes && pos + numtimes < buf.len)
66 memset(buf.str + pos, c, numtimes);
69 size_t slack()
const {
return pos <= buf.len ? buf.len - pos : 0; }
70 size_t excess()
const {
return pos > buf.len ? pos - buf.len : 0; }
72 csubstr curr()
const {
return pos <= buf.len ? buf.first(pos) : buf; }
74 substr rem()
const {
return pos < buf.len ? buf.sub(pos) : buf.last(0); }
76 size_t advance(
size_t more) { pos += more;
return pos; }
82 inline C4_NO_INLINE csubstr _maybe_add_ellipsis(substr buf,
size_t len)
84 if(C4_UNLIKELY(len > buf.len))
86 const size_t numdots = (buf.len > 3) ? 3 : buf.len;
87 buf.last(numdots).fill(
'.');
90 return buf.first(len);
94 template<
class T>
struct dump_directly_ :
public std::false_type {};
95 template<>
struct dump_directly_<csubstr> :
public std::true_type {};
96 template<>
struct dump_directly_< substr> :
public std::true_type {};
97 template<>
struct dump_directly_<const char*> :
public std::true_type {};
98 template<>
struct dump_directly_< char*> :
public std::true_type {};
99 template<
size_t N>
struct dump_directly_<const char (&)[N]> :
public std::true_type {};
100 template<
size_t N>
struct dump_directly_< char (&)[N]> :
public std::true_type {};
101 template<
size_t N>
struct dump_directly_<const char[N]> :
public std::true_type {};
102 template<
size_t N>
struct dump_directly_< char[N]> :
public std::true_type {};
103 template<
class T>
using dump_directly = dump_directly_<typename std::remove_cv<typename std::remove_reference<T>::type>::type>;
106 C4_NO_INLINE
auto _to_chars_limited(substr buf, T &&var)
107 ->
typename std::enable_if< ! detail::dump_directly<T>::value, csubstr>::type
109 size_t len =
to_chars(buf, std::forward<T>(var));
110 return _maybe_add_ellipsis(buf, len);
113 C4_NO_INLINE
auto _to_chars_limited(substr, T &&var)
114 ->
typename std::enable_if<detail::dump_directly<T>::value, csubstr>::type
121 template<
class DumpFn>
122 C4_NO_INLINE
void _dump(DumpFn &&dumpfn, substr, csubstr fmt)
124 std::forward<DumpFn>(dumpfn)(fmt);
126 template<
class DumpFn,
class Arg,
class ...Args>
127 C4_NO_INLINE
void _dump(DumpFn &&dumpfn, substr argbuf, csubstr fmt, Arg
const& arg, Args
const& ...more)
129 size_t pos = fmt.find(
"{}");
131 return std::forward<DumpFn>(dumpfn)(fmt);
132 std::forward<DumpFn>(dumpfn)(fmt.first(pos));
133 std::forward<DumpFn>(dumpfn)(_to_chars_limited(argbuf, arg));
134 _dump(std::forward<DumpFn>(dumpfn), argbuf, fmt.sub(pos + 2), more...);
138 template<
class ...Args>
139 C4_NO_INLINE csubstr _mk_err_msg(substr buf, csubstr fmt, Args
const& ...args)
141 detail::_SubstrWriter writer(buf);
142 auto dumpfn = [&writer](csubstr s){ writer.append(s); };
144 _dump(dumpfn, writebuf, fmt, args...);
145 return _maybe_add_ellipsis(buf, writer.pos);
186 template<
class DumpFn>
187 C4_NO_INLINE
size_t location_format(DumpFn &&dumpfn, Location
const& loc);
260 template<
class DumpFn>
262 Location
const &location,
263 csubstr source_buffer,
265 size_t num_lines_before = 3,
266 size_t num_lines_after = 0,
267 size_t first_col_highlight = 0,
268 size_t last_col_highlight = 0,
269 size_t maxlen = 80u);
297 template<
class DumpFn>
298 C4_NO_INLINE
void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic
const& errdata);
301 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(Callbacks
const& callbacks, ErrorDataBasic
const& errdata,
const char* msg_);
303 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(ErrorDataBasic
const& errdata,
const char* msg);
305 template<
class ...Args>
309 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
312 C4_UNREACHABLE_AFTER_ERR();
315 template<
class ...Args>
319 C4_UNREACHABLE_AFTER_ERR();
352 template<
class DumpFn>
353 C4_NO_INLINE
void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse
const& errdata);
356 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(Callbacks
const& callbacks, ErrorDataParse
const& errdata,
const char *msg);
358 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(ErrorDataParse
const& errdata,
const char *msg);
360 template<
class ...Args>
364 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
371 C4_UNREACHABLE_AFTER_ERR();
374 template<
class ...Args>
378 C4_UNREACHABLE_AFTER_ERR();
413 template<
class DumpFn>
414 C4_NO_INLINE
void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit
const& errdata);
418 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(Callbacks
const& callbacks, ErrorDataVisit
const& errdata,
const char *msg);
420 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(ErrorDataVisit
const& errdata,
const char *msg);
422 template<
class ...Args>
426 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
433 C4_UNREACHABLE_AFTER_ERR();
436 template<
class ...Args>
440 C4_UNREACHABLE_AFTER_ERR();
446 #if defined(_RYML_WITH_EXCEPTIONS) || defined(__DOXYGEN__)
458 const char*
what() const noexcept
override {
return msg; }
503 template<
class CharContainer>
508 out->append(s.str, s.len);
516 template<
class CharContainer>
521 out->append(s.str, s.len);
529 template<
class CharContainer>
534 out->append(s.str, s.len);
543 template<
class CharContainer,
class ExceptionT>
564 # define _RYML_ASSERT_BASIC(cond) _RYML_CHECK_BASIC(cond)
565 # define _RYML_ASSERT_BASIC_(cb, cond) _RYML_CHECK_BASIC_((cb), cond)
566 # define _RYML_ASSERT_BASIC_MSG(cond, ...) _RYML_CHECK_BASIC_MSG(cond, __VA_ARGS__)
567 # define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...) _RYML_CHECK_BASIC_MSG_((cb), cond, __VA_ARGS__)
568 # define _RYML_ASSERT_PARSE(cond, ymlloc) _RYML_CHECK_PARSE(cond, (ymlloc))
569 # define _RYML_ASSERT_PARSE_(cb, cond, ymlloc) _RYML_CHECK_PARSE_((cb), cond, (ymlloc))
570 # define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG(cond, (ymlloc), __VA_ARGS__)
571 # define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG_((cb), cond, (ymlloc), __VA_ARGS__)
572 # define _RYML_ASSERT_VISIT(cond, tree, node) _RYML_CHECK_VISIT(cond, (tree), (node))
573 # define _RYML_ASSERT_VISIT_(cb, cond, tree, node) _RYML_CHECK_VISIT_((cb), cond, (tree), (node))
574 # define _RYML_ASSERT_VISIT_MSG(cond, tree, node, ...) _RYML_CHECK_VISIT_MSG(cond, (tree), (node), __VA_ARGS__)
575 # define _RYML_ASSERT_VISIT_MSG_(cb, cond, tree, node, ...) _RYML_CHECK_VISIT_MSG_((cb), cond, (tree), (node), __VA_ARGS__)
577 # define _RYML_ASSERT_BASIC(cond)
578 # define _RYML_ASSERT_BASIC_(cb, cond)
579 # define _RYML_ASSERT_BASIC_MSG(cond, ...)
580 # define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...)
581 # define _RYML_ASSERT_PARSE(cond, ymlloc)
582 # define _RYML_ASSERT_PARSE_(cb, cond, ymlloc)
583 # define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...)
584 # define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...)
585 # define _RYML_ASSERT_VISIT(cont, tree, node)
586 # define _RYML_ASSERT_VISIT_(cb, cont, tree, node)
587 # define _RYML_ASSERT_VISIT_MSG(cont, tree, node, ...)
588 # define _RYML_ASSERT_VISIT_MSG_(cb, cont, tree, node, ...)
591 #define _RYML_ERR_BASIC(...) \
594 RYML_DEBUG_BREAK(); \
595 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
596 C4_UNREACHABLE_AFTER_ERR(); \
598 #define _RYML_ERR_PARSE(ymlloc, ...) \
601 RYML_DEBUG_BREAK(); \
602 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
603 C4_UNREACHABLE_AFTER_ERR(); \
605 #define _RYML_ERR_VISIT(tree, node, ...) \
608 RYML_DEBUG_BREAK(); \
609 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
610 C4_UNREACHABLE_AFTER_ERR(); \
614 #define _RYML_ERR_BASIC_(cb, ...) \
617 RYML_DEBUG_BREAK(); \
618 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
619 C4_UNREACHABLE_AFTER_ERR(); \
621 #define _RYML_ERR_PARSE_(cb, ymlloc, ...) \
624 RYML_DEBUG_BREAK(); \
625 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
626 C4_UNREACHABLE_AFTER_ERR(); \
628 #define _RYML_ERR_VISIT_(cb, tree, node, ...) \
631 RYML_DEBUG_BREAK(); \
632 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
633 C4_UNREACHABLE_AFTER_ERR(); \
637 #ifndef RYML_SHORT_CHECK_MSG
638 #define _RYML_MAYBE_MSG(cond) ": " #cond
639 #define _RYML_MAYBE_MSG_(cond) ": " #cond ": "
641 #define _RYML_MAYBE_MSG(cond)
642 #define _RYML_MAYBE_MSG_(cond) ": "
645 #define _RYML_CHECK_BASIC(cond) \
647 if(C4_UNLIKELY(!(cond))) \
649 RYML_DEBUG_BREAK(); \
650 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
651 C4_UNREACHABLE_AFTER_ERR(); \
654 #define _RYML_CHECK_PARSE(cond, ymlloc) \
656 if(C4_UNLIKELY(!(cond))) \
658 RYML_DEBUG_BREAK(); \
659 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
660 C4_UNREACHABLE_AFTER_ERR(); \
663 #define _RYML_CHECK_VISIT(cond, tree, node) \
665 if(C4_UNLIKELY(!(cond))) \
667 RYML_DEBUG_BREAK(); \
668 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
669 C4_UNREACHABLE_AFTER_ERR(); \
674 #define _RYML_CHECK_BASIC_(cb, cond) \
676 if(C4_UNLIKELY(!(cond))) \
678 RYML_DEBUG_BREAK(); \
679 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
680 C4_UNREACHABLE_AFTER_ERR(); \
683 #define _RYML_CHECK_PARSE_(cb, cond, ymlloc) \
685 if(C4_UNLIKELY(!(cond))) \
687 RYML_DEBUG_BREAK(); \
688 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
689 C4_UNREACHABLE_AFTER_ERR(); \
692 #define _RYML_CHECK_VISIT_(cb, cond, tree, node) \
694 if(C4_UNLIKELY(!(cond))) \
696 RYML_DEBUG_BREAK(); \
697 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
698 C4_UNREACHABLE_AFTER_ERR(); \
703 #define _RYML_CHECK_BASIC_MSG(cond, ...) \
705 if(C4_UNLIKELY(!(cond))) \
707 RYML_DEBUG_BREAK(); \
708 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
709 C4_UNREACHABLE_AFTER_ERR(); \
712 #define _RYML_CHECK_PARSE_MSG(cond, ymlloc, ...) \
714 if(C4_UNLIKELY(!(cond))) \
716 RYML_DEBUG_BREAK(); \
717 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
718 C4_UNREACHABLE_AFTER_ERR(); \
721 #define _RYML_CHECK_VISIT_MSG(cond, tree, node, ...) \
723 if(C4_UNLIKELY(!(cond))) \
725 RYML_DEBUG_BREAK(); \
726 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
727 C4_UNREACHABLE_AFTER_ERR(); \
732 #define _RYML_CHECK_BASIC_MSG_(cb, cond, ...) \
734 if(C4_UNLIKELY(!(cond))) \
736 RYML_DEBUG_BREAK(); \
737 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
738 C4_UNREACHABLE_AFTER_ERR(); \
741 #define _RYML_CHECK_PARSE_MSG_(cb, cond, ymlloc, ...) \
743 if(C4_UNLIKELY(!(cond))) \
745 RYML_DEBUG_BREAK(); \
746 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
747 C4_UNREACHABLE_AFTER_ERR(); \
750 #define _RYML_CHECK_VISIT_MSG_(cb, cond, tree, node, ...) \
752 if(C4_UNLIKELY(!(cond))) \
754 RYML_DEBUG_BREAK(); \
755 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
756 C4_UNREACHABLE_AFTER_ERR(); \
Common utilities and infrastructure used by ryml.
#define RYML_ERRMSG_SIZE
size for the error message buffer
#define RYML_LOGBUF_SIZE
size for the buffer used to format individual values to string while preparing an error message....
Callbacks const & get_callbacks()
get the global callbacks
size_t location_format(DumpFn &&dumpfn, Location const &loc)
generic formatting of a location
void err_visit(ErrorDataVisit const &errdata, const char *msg)
trigger a visit error to its respective handler, with a non-formatted error message.
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.
void err_basic(ErrorDataBasic const &errdata, const char *msg)
trigger a basic error to its respective handler, with a non-formatted error message.
void location_format_with_context(DumpFn &&dumpfn, Location const &location, csubstr source_buffer, csubstr call, size_t num_lines_before, size_t num_lines_after, size_t first_col_highlight, size_t last_col_highlight, size_t maxlen)
Generic formatting of a location, printing the source code buffer region around the location.
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.
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.
void format_exc(CharContainer *out, ExceptionBasic const &exc)
Format a basic exception to an existing char container.
void err_parse(ErrorDataParse const &errdata, const char *msg)
trigger a parse error to its respective handler, with a non-formatted error message.
csubstr to_csubstr(substr s) noexcept
neutral version for use in generic code
csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
@ npos
a null string position
size_t to_chars(substr buf, escaped_scalar e)
formatting implementation to escape a scalar with x
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
A c-style callbacks class to customize behavior on errors or allocation.
pfn_error_basic m_error_basic
a pointer to a basic error handler function
pfn_error_parse m_error_parse
a pointer to a parse error handler function
void * m_user_data
data to be forwarded in every call to a callback
pfn_error_visit m_error_visit
a pointer to a visit error handler function
Location ymlloc
location in the YAML source buffer where the error was detected.
Location cpploc
location in the C++ source file where the error was detected.
Exception thrown by the default basic error implementation.
ErrorDataBasic errdata_basic
error data
ExceptionBasic(csubstr msg, ErrorDataBasic const &errdata_) noexcept
char msg[RYML_ERRMSG_SIZE]
the reported error message, without location indication.
const char * what() const noexcept override
Exception thrown by the default parse error implementation.
ExceptionParse(csubstr msg, ErrorDataParse const &errdata_) noexcept
ErrorDataParse errdata_parse
Exception thrown by the default visit error implementation.
ErrorDataVisit errdata_visit
ExceptionVisit(csubstr msg, ErrorDataVisit const &errdata_) noexcept