1 #ifndef _C4_YML_ERROR_HPP_
2 #define _C4_YML_ERROR_HPP_
6 #ifndef _C4_YML_COMMON_HPP_
13 #if (defined(C4_EXCEPTIONS) && (!defined(RYML_NO_DEFAULT_CALLBACKS) && defined(RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS))) || defined(__DOXYGEN__)
14 #define _RYML_WITH_EXCEPTIONS
16 #if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
17 # define RYML_DEBUG_BREAK() \
19 if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
25 # define RYML_DEBUG_BREAK()
29 #ifdef _RYML_WITH_EXCEPTIONS
45 _SubstrWriter(substr buf_,
size_t pos_=0) : buf(buf_), pos(pos_) { C4_ASSERT(buf.str); }
46 void append(csubstr s)
48 C4_ASSERT(!s.overlaps(buf));
49 C4_ASSERT(s.str || !s.len);
50 if(s.len && pos + s.len <= buf.len)
53 memcpy(buf.str + pos, s.str, s.len);
64 void append_n(
char c,
size_t numtimes)
67 if(numtimes && pos + numtimes < buf.len)
68 memset(buf.str + pos, c, numtimes);
71 size_t slack()
const {
return pos <= buf.len ? buf.len - pos : 0; }
72 size_t excess()
const {
return pos > buf.len ? pos - buf.len : 0; }
74 csubstr curr()
const {
return pos <= buf.len ? buf.first(pos) : buf; }
76 substr rem()
const {
return pos < buf.len ? buf.sub(pos) : buf.last(0); }
78 size_t advance(
size_t more) { pos += more;
return pos; }
84 inline C4_NO_INLINE csubstr _maybe_add_ellipsis(substr buf,
size_t len)
86 if(C4_UNLIKELY(len > buf.len))
88 const size_t numdots = (buf.len > 3) ? 3 : buf.len;
89 buf.last(numdots).fill(
'.');
92 return buf.first(len);
100 using type =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
103 struct _dump_directly :
public c4::is_string<typename _remove_cvref<T>::type>
109 template<
class T>
using _remove_cvref_t =
typename _remove_cvref<T>::type;
110 template<
class T>
using _dump_directly_v =
typename _dump_directly<T>::value;
112 C4_NO_INLINE csubstr _to_chars_limited(substr buf, T &&var)
114 if constexpr (_dump_directly<T>::value)
121 size_t len =
to_chars(buf, std::forward<T>(var));
122 return _maybe_add_ellipsis(buf, len);
127 C4_NO_INLINE
auto _to_chars_limited(substr, T &&var)
128 ->
typename std::enable_if<_dump_directly<T>::value, csubstr>::type
133 C4_NO_INLINE
auto _to_chars_limited(substr buf, T &&var)
134 ->
typename std::enable_if< ! _dump_directly<T>::value, csubstr>::type
136 size_t len =
to_chars(buf, std::forward<T>(var));
137 return _maybe_add_ellipsis(buf, len);
143 template<
class DumpFn>
144 C4_NO_INLINE
void _dump(DumpFn &&dumpfn, substr, csubstr fmt)
146 std::forward<DumpFn>(dumpfn)(fmt);
148 template<
class DumpFn,
class Arg,
class ...Args>
149 C4_NO_INLINE
void _dump(DumpFn &&dumpfn, substr argbuf, csubstr fmt, Arg
const& arg, Args
const& ...more)
151 size_t pos = fmt.find(
"{}");
153 return std::forward<DumpFn>(dumpfn)(fmt);
154 std::forward<DumpFn>(dumpfn)(fmt.first(pos));
155 std::forward<DumpFn>(dumpfn)(_to_chars_limited(argbuf, arg));
156 _dump(std::forward<DumpFn>(dumpfn), argbuf, fmt.sub(pos + 2), more...);
160 template<
class ...Args>
161 C4_NO_INLINE csubstr _mk_err_msg(substr buf, csubstr fmt, Args
const& ...args)
163 detail::_SubstrWriter writer(buf);
164 auto dumpfn = [&writer](csubstr s){ writer.append(s); };
166 _dump(dumpfn, writebuf, fmt, args...);
167 return _maybe_add_ellipsis(buf, writer.pos);
208 template<
class DumpFn>
209 C4_NO_INLINE
size_t location_format(DumpFn &&dumpfn, Location
const& loc);
282 template<
class DumpFn>
284 Location
const &location,
285 csubstr source_buffer,
287 size_t num_lines_before = 3,
288 size_t num_lines_after = 0,
289 size_t first_col_highlight = 0,
290 size_t last_col_highlight = 0,
291 size_t maxlen = 80u);
319 template<
class DumpFn>
320 C4_NO_INLINE
void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic
const& errdata);
323 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(Callbacks
const& callbacks, ErrorDataBasic
const& errdata,
const char* msg_);
325 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(ErrorDataBasic
const& errdata,
const char* msg);
327 template<
class ...Args>
331 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
334 C4_UNREACHABLE_AFTER_ERR();
337 template<
class ...Args>
341 C4_UNREACHABLE_AFTER_ERR();
374 template<
class DumpFn>
375 C4_NO_INLINE
void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse
const& errdata);
378 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(Callbacks
const& callbacks, ErrorDataParse
const& errdata,
const char *msg);
380 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(ErrorDataParse
const& errdata,
const char *msg);
382 template<
class ...Args>
386 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
393 C4_UNREACHABLE_AFTER_ERR();
396 template<
class ...Args>
400 C4_UNREACHABLE_AFTER_ERR();
435 template<
class DumpFn>
436 C4_NO_INLINE
void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit
const& errdata);
440 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(Callbacks
const& callbacks, ErrorDataVisit
const& errdata,
const char *msg);
442 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(ErrorDataVisit
const& errdata,
const char *msg);
444 template<
class ...Args>
448 csubstr msg = detail::_mk_err_msg(errbuf,
to_csubstr(fmt), args...);
455 C4_UNREACHABLE_AFTER_ERR();
458 template<
class ...Args>
462 C4_UNREACHABLE_AFTER_ERR();
468 #if defined(_RYML_WITH_EXCEPTIONS) || defined(__DOXYGEN__)
480 const char*
what() const noexcept
override {
return msg; }
525 template<
class CharContainer>
530 out->append(s.str, s.len);
538 template<
class CharContainer>
543 out->append(s.str, s.len);
551 template<
class CharContainer>
556 out->append(s.str, s.len);
565 template<
class CharContainer,
class ExceptionT>
586 # define _RYML_ASSERT_BASIC(cond) _RYML_CHECK_BASIC(cond)
587 # define _RYML_ASSERT_BASIC_(cb, cond) _RYML_CHECK_BASIC_((cb), cond)
588 # define _RYML_ASSERT_BASIC_MSG(cond, ...) _RYML_CHECK_BASIC_MSG(cond, __VA_ARGS__)
589 # define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...) _RYML_CHECK_BASIC_MSG_((cb), cond, __VA_ARGS__)
590 # define _RYML_ASSERT_PARSE(cond, ymlloc) _RYML_CHECK_PARSE(cond, (ymlloc))
591 # define _RYML_ASSERT_PARSE_(cb, cond, ymlloc) _RYML_CHECK_PARSE_((cb), cond, (ymlloc))
592 # define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG(cond, (ymlloc), __VA_ARGS__)
593 # define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG_((cb), cond, (ymlloc), __VA_ARGS__)
594 # define _RYML_ASSERT_VISIT(cond, tree, node) _RYML_CHECK_VISIT(cond, (tree), (node))
595 # define _RYML_ASSERT_VISIT_(cb, cond, tree, node) _RYML_CHECK_VISIT_((cb), cond, (tree), (node))
596 # define _RYML_ASSERT_VISIT_MSG(cond, tree, node, ...) _RYML_CHECK_VISIT_MSG(cond, (tree), (node), __VA_ARGS__)
597 # define _RYML_ASSERT_VISIT_MSG_(cb, cond, tree, node, ...) _RYML_CHECK_VISIT_MSG_((cb), cond, (tree), (node), __VA_ARGS__)
599 # define _RYML_ASSERT_BASIC(cond)
600 # define _RYML_ASSERT_BASIC_(cb, cond)
601 # define _RYML_ASSERT_BASIC_MSG(cond, ...)
602 # define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...)
603 # define _RYML_ASSERT_PARSE(cond, ymlloc)
604 # define _RYML_ASSERT_PARSE_(cb, cond, ymlloc)
605 # define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...)
606 # define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...)
607 # define _RYML_ASSERT_VISIT(cont, tree, node)
608 # define _RYML_ASSERT_VISIT_(cb, cont, tree, node)
609 # define _RYML_ASSERT_VISIT_MSG(cont, tree, node, ...)
610 # define _RYML_ASSERT_VISIT_MSG_(cb, cont, tree, node, ...)
613 #define _RYML_ERR_BASIC(...) \
616 RYML_DEBUG_BREAK(); \
617 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
618 C4_UNREACHABLE_AFTER_ERR(); \
620 #define _RYML_ERR_PARSE(ymlloc, ...) \
623 RYML_DEBUG_BREAK(); \
624 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
625 C4_UNREACHABLE_AFTER_ERR(); \
627 #define _RYML_ERR_VISIT(tree, node, ...) \
630 RYML_DEBUG_BREAK(); \
631 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
632 C4_UNREACHABLE_AFTER_ERR(); \
636 #define _RYML_ERR_BASIC_(cb, ...) \
639 RYML_DEBUG_BREAK(); \
640 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
641 C4_UNREACHABLE_AFTER_ERR(); \
643 #define _RYML_ERR_PARSE_(cb, ymlloc, ...) \
646 RYML_DEBUG_BREAK(); \
647 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
648 C4_UNREACHABLE_AFTER_ERR(); \
650 #define _RYML_ERR_VISIT_(cb, tree, node, ...) \
653 RYML_DEBUG_BREAK(); \
654 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
655 C4_UNREACHABLE_AFTER_ERR(); \
659 #ifndef RYML_SHORT_CHECK_MSG
660 #define _RYML_MAYBE_MSG(cond) ": " #cond
661 #define _RYML_MAYBE_MSG_(cond) ": " #cond ": "
663 #define _RYML_MAYBE_MSG(cond)
664 #define _RYML_MAYBE_MSG_(cond) ": "
667 #define _RYML_CHECK_BASIC(cond) \
669 if(C4_UNLIKELY(!(cond))) \
671 RYML_DEBUG_BREAK(); \
672 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
673 C4_UNREACHABLE_AFTER_ERR(); \
676 #define _RYML_CHECK_PARSE(cond, ymlloc) \
678 if(C4_UNLIKELY(!(cond))) \
680 RYML_DEBUG_BREAK(); \
681 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
682 C4_UNREACHABLE_AFTER_ERR(); \
685 #define _RYML_CHECK_VISIT(cond, tree, node) \
687 if(C4_UNLIKELY(!(cond))) \
689 RYML_DEBUG_BREAK(); \
690 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
691 C4_UNREACHABLE_AFTER_ERR(); \
696 #define _RYML_CHECK_BASIC_(cb, cond) \
698 if(C4_UNLIKELY(!(cond))) \
700 RYML_DEBUG_BREAK(); \
701 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
702 C4_UNREACHABLE_AFTER_ERR(); \
705 #define _RYML_CHECK_PARSE_(cb, cond, ymlloc) \
707 if(C4_UNLIKELY(!(cond))) \
709 RYML_DEBUG_BREAK(); \
710 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
711 C4_UNREACHABLE_AFTER_ERR(); \
714 #define _RYML_CHECK_VISIT_(cb, cond, tree, node) \
716 if(C4_UNLIKELY(!(cond))) \
718 RYML_DEBUG_BREAK(); \
719 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
720 C4_UNREACHABLE_AFTER_ERR(); \
725 #define _RYML_CHECK_BASIC_MSG(cond, ...) \
727 if(C4_UNLIKELY(!(cond))) \
729 RYML_DEBUG_BREAK(); \
730 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
731 C4_UNREACHABLE_AFTER_ERR(); \
734 #define _RYML_CHECK_PARSE_MSG(cond, ymlloc, ...) \
736 if(C4_UNLIKELY(!(cond))) \
738 RYML_DEBUG_BREAK(); \
739 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
740 C4_UNREACHABLE_AFTER_ERR(); \
743 #define _RYML_CHECK_VISIT_MSG(cond, tree, node, ...) \
745 if(C4_UNLIKELY(!(cond))) \
747 RYML_DEBUG_BREAK(); \
748 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
749 C4_UNREACHABLE_AFTER_ERR(); \
754 #define _RYML_CHECK_BASIC_MSG_(cb, cond, ...) \
756 if(C4_UNLIKELY(!(cond))) \
758 RYML_DEBUG_BREAK(); \
759 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
760 C4_UNREACHABLE_AFTER_ERR(); \
763 #define _RYML_CHECK_PARSE_MSG_(cb, cond, ymlloc, ...) \
765 if(C4_UNLIKELY(!(cond))) \
767 RYML_DEBUG_BREAK(); \
768 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
769 C4_UNREACHABLE_AFTER_ERR(); \
772 #define _RYML_CHECK_VISIT_MSG_(cb, cond, tree, node, ...) \
774 if(C4_UNLIKELY(!(cond))) \
776 RYML_DEBUG_BREAK(); \
777 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
778 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