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);
98 using type =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
101 struct _dump_directly :
public c4::is_string<typename _remove_cvref<T>::type>
107 template<
class T>
using _remove_cvref_t =
typename _remove_cvref<T>::type;
108 template<
class T>
using _dump_directly_v =
typename _dump_directly<T>::value;
110 C4_NO_INLINE csubstr _to_chars_limited(substr buf, T &&var)
112 if constexpr (_dump_directly<T>::value)
119 size_t len =
to_chars(buf, std::forward<T>(var));
120 return _maybe_add_ellipsis(buf, len);
125 C4_NO_INLINE
auto _to_chars_limited(substr, T &&var)
126 ->
typename std::enable_if<_dump_directly<T>::value, csubstr>::type
131 C4_NO_INLINE
auto _to_chars_limited(substr buf, T &&var)
132 ->
typename std::enable_if< ! _dump_directly<T>::value, csubstr>::type
134 size_t len =
to_chars(buf, std::forward<T>(var));
135 return _maybe_add_ellipsis(buf, len);
141 template<
class DumpFn>
142 C4_NO_INLINE
void _dump(DumpFn &&dumpfn, substr, csubstr fmt)
144 std::forward<DumpFn>(dumpfn)(fmt);
146 template<
class DumpFn,
class Arg,
class ...Args>
147 C4_NO_INLINE
void _dump(DumpFn &&dumpfn, substr argbuf, csubstr fmt, Arg
const& arg, Args
const& ...more)
149 size_t pos = fmt.find(
"{}");
151 return std::forward<DumpFn>(dumpfn)(fmt);
152 std::forward<DumpFn>(dumpfn)(fmt.first(pos));
153 std::forward<DumpFn>(dumpfn)(_to_chars_limited(argbuf, arg));
154 _dump(std::forward<DumpFn>(dumpfn), argbuf, fmt.sub(pos + 2), more...);
158 template<
class ...Args>
159 C4_NO_INLINE csubstr _mk_err_msg(substr buf, csubstr fmt, Args
const& ...args)
161 detail::_SubstrWriter writer(buf);
162 auto dumpfn = [&writer](csubstr s){ writer.append(s); };
164 _dump(dumpfn, writebuf, fmt, args...);
165 return _maybe_add_ellipsis(buf, writer.pos);
206 template<
class DumpFn>
207 C4_NO_INLINE
size_t location_format(DumpFn &&dumpfn, Location
const& loc);
280 template<
class DumpFn>
282 Location
const &location,
283 csubstr source_buffer,
285 size_t num_lines_before = 3,
286 size_t num_lines_after = 0,
287 size_t first_col_highlight = 0,
288 size_t last_col_highlight = 0,
289 size_t maxlen = 80u);
317 template<
class DumpFn>
318 C4_NO_INLINE
void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic
const& errdata);
321 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(Callbacks
const& callbacks, ErrorDataBasic
const& errdata,
const char* msg_);
323 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(ErrorDataBasic
const& errdata,
const char* msg);
325 template<
class ...Args>
329 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
332 C4_UNREACHABLE_AFTER_ERR();
335 template<
class ...Args>
339 C4_UNREACHABLE_AFTER_ERR();
372 template<
class DumpFn>
373 C4_NO_INLINE
void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse
const& errdata);
376 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(Callbacks
const& callbacks, ErrorDataParse
const& errdata,
const char *msg);
378 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(ErrorDataParse
const& errdata,
const char *msg);
380 template<
class ...Args>
384 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
391 C4_UNREACHABLE_AFTER_ERR();
394 template<
class ...Args>
398 C4_UNREACHABLE_AFTER_ERR();
433 template<
class DumpFn>
434 C4_NO_INLINE
void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit
const& errdata);
438 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(Callbacks
const& callbacks, ErrorDataVisit
const& errdata,
const char *msg);
440 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(ErrorDataVisit
const& errdata,
const char *msg);
442 template<
class ...Args>
446 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
453 C4_UNREACHABLE_AFTER_ERR();
456 template<
class ...Args>
460 C4_UNREACHABLE_AFTER_ERR();
466 #if defined(_RYML_WITH_EXCEPTIONS) || defined(__DOXYGEN__)
478 const char*
what() const noexcept
override {
return msg; }
523 template<
class CharContainer>
528 out->append(s.str, s.len);
536 template<
class CharContainer>
541 out->append(s.str, s.len);
549 template<
class CharContainer>
554 out->append(s.str, s.len);
563 template<
class CharContainer,
class ExceptionT>
584 # define _RYML_ASSERT_BASIC(cond) _RYML_CHECK_BASIC(cond)
585 # define _RYML_ASSERT_BASIC_(cb, cond) _RYML_CHECK_BASIC_((cb), cond)
586 # define _RYML_ASSERT_BASIC_MSG(cond, ...) _RYML_CHECK_BASIC_MSG(cond, __VA_ARGS__)
587 # define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...) _RYML_CHECK_BASIC_MSG_((cb), cond, __VA_ARGS__)
588 # define _RYML_ASSERT_PARSE(cond, ymlloc) _RYML_CHECK_PARSE(cond, (ymlloc))
589 # define _RYML_ASSERT_PARSE_(cb, cond, ymlloc) _RYML_CHECK_PARSE_((cb), cond, (ymlloc))
590 # define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG(cond, (ymlloc), __VA_ARGS__)
591 # define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG_((cb), cond, (ymlloc), __VA_ARGS__)
592 # define _RYML_ASSERT_VISIT(cond, tree, node) _RYML_CHECK_VISIT(cond, (tree), (node))
593 # define _RYML_ASSERT_VISIT_(cb, cond, tree, node) _RYML_CHECK_VISIT_((cb), cond, (tree), (node))
594 # define _RYML_ASSERT_VISIT_MSG(cond, tree, node, ...) _RYML_CHECK_VISIT_MSG(cond, (tree), (node), __VA_ARGS__)
595 # define _RYML_ASSERT_VISIT_MSG_(cb, cond, tree, node, ...) _RYML_CHECK_VISIT_MSG_((cb), cond, (tree), (node), __VA_ARGS__)
597 # define _RYML_ASSERT_BASIC(cond)
598 # define _RYML_ASSERT_BASIC_(cb, cond)
599 # define _RYML_ASSERT_BASIC_MSG(cond, ...)
600 # define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...)
601 # define _RYML_ASSERT_PARSE(cond, ymlloc)
602 # define _RYML_ASSERT_PARSE_(cb, cond, ymlloc)
603 # define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...)
604 # define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...)
605 # define _RYML_ASSERT_VISIT(cont, tree, node)
606 # define _RYML_ASSERT_VISIT_(cb, cont, tree, node)
607 # define _RYML_ASSERT_VISIT_MSG(cont, tree, node, ...)
608 # define _RYML_ASSERT_VISIT_MSG_(cb, cont, tree, node, ...)
611 #define _RYML_ERR_BASIC(...) \
614 RYML_DEBUG_BREAK(); \
615 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
616 C4_UNREACHABLE_AFTER_ERR(); \
618 #define _RYML_ERR_PARSE(ymlloc, ...) \
621 RYML_DEBUG_BREAK(); \
622 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
623 C4_UNREACHABLE_AFTER_ERR(); \
625 #define _RYML_ERR_VISIT(tree, node, ...) \
628 RYML_DEBUG_BREAK(); \
629 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
630 C4_UNREACHABLE_AFTER_ERR(); \
634 #define _RYML_ERR_BASIC_(cb, ...) \
637 RYML_DEBUG_BREAK(); \
638 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
639 C4_UNREACHABLE_AFTER_ERR(); \
641 #define _RYML_ERR_PARSE_(cb, ymlloc, ...) \
644 RYML_DEBUG_BREAK(); \
645 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
646 C4_UNREACHABLE_AFTER_ERR(); \
648 #define _RYML_ERR_VISIT_(cb, tree, node, ...) \
651 RYML_DEBUG_BREAK(); \
652 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
653 C4_UNREACHABLE_AFTER_ERR(); \
657 #ifndef RYML_SHORT_CHECK_MSG
658 #define _RYML_MAYBE_MSG(cond) ": " #cond
659 #define _RYML_MAYBE_MSG_(cond) ": " #cond ": "
661 #define _RYML_MAYBE_MSG(cond)
662 #define _RYML_MAYBE_MSG_(cond) ": "
665 #define _RYML_CHECK_BASIC(cond) \
667 if(C4_UNLIKELY(!(cond))) \
669 RYML_DEBUG_BREAK(); \
670 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
671 C4_UNREACHABLE_AFTER_ERR(); \
674 #define _RYML_CHECK_PARSE(cond, ymlloc) \
676 if(C4_UNLIKELY(!(cond))) \
678 RYML_DEBUG_BREAK(); \
679 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
680 C4_UNREACHABLE_AFTER_ERR(); \
683 #define _RYML_CHECK_VISIT(cond, tree, node) \
685 if(C4_UNLIKELY(!(cond))) \
687 RYML_DEBUG_BREAK(); \
688 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
689 C4_UNREACHABLE_AFTER_ERR(); \
694 #define _RYML_CHECK_BASIC_(cb, cond) \
696 if(C4_UNLIKELY(!(cond))) \
698 RYML_DEBUG_BREAK(); \
699 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
700 C4_UNREACHABLE_AFTER_ERR(); \
703 #define _RYML_CHECK_PARSE_(cb, cond, ymlloc) \
705 if(C4_UNLIKELY(!(cond))) \
707 RYML_DEBUG_BREAK(); \
708 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
709 C4_UNREACHABLE_AFTER_ERR(); \
712 #define _RYML_CHECK_VISIT_(cb, cond, tree, node) \
714 if(C4_UNLIKELY(!(cond))) \
716 RYML_DEBUG_BREAK(); \
717 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
718 C4_UNREACHABLE_AFTER_ERR(); \
723 #define _RYML_CHECK_BASIC_MSG(cond, ...) \
725 if(C4_UNLIKELY(!(cond))) \
727 RYML_DEBUG_BREAK(); \
728 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
729 C4_UNREACHABLE_AFTER_ERR(); \
732 #define _RYML_CHECK_PARSE_MSG(cond, ymlloc, ...) \
734 if(C4_UNLIKELY(!(cond))) \
736 RYML_DEBUG_BREAK(); \
737 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
738 C4_UNREACHABLE_AFTER_ERR(); \
741 #define _RYML_CHECK_VISIT_MSG(cond, tree, node, ...) \
743 if(C4_UNLIKELY(!(cond))) \
745 RYML_DEBUG_BREAK(); \
746 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
747 C4_UNREACHABLE_AFTER_ERR(); \
752 #define _RYML_CHECK_BASIC_MSG_(cb, cond, ...) \
754 if(C4_UNLIKELY(!(cond))) \
756 RYML_DEBUG_BREAK(); \
757 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
758 C4_UNREACHABLE_AFTER_ERR(); \
761 #define _RYML_CHECK_PARSE_MSG_(cb, cond, ymlloc, ...) \
763 if(C4_UNLIKELY(!(cond))) \
765 RYML_DEBUG_BREAK(); \
766 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
767 C4_UNREACHABLE_AFTER_ERR(); \
770 #define _RYML_CHECK_VISIT_MSG_(cb, cond, tree, node, ...) \
772 if(C4_UNLIKELY(!(cond))) \
774 RYML_DEBUG_BREAK(); \
775 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
776 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 escape_scalar()
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
a traits class to mark a type as a string type (meaning c4::to_csubstr() can be used directly).
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