1 #ifndef C4_YML_ERROR_HPP_
2 #define C4_YML_ERROR_HPP_
6 #ifndef C4_YML_COMMON_HPP_
9 #ifndef C4_CHARCONV_HPP_
16 #if (defined(C4_EXCEPTIONS) && (!defined(RYML_NO_DEFAULT_CALLBACKS) && defined(RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS))) || defined(__DOXYGEN__)
17 #define RYML_WITH_EXCEPTIONS_
19 #if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
20 # define RYML_DEBUG_BREAK() \
22 if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
28 # define RYML_DEBUG_BREAK()
32 #ifdef RYML_WITH_EXCEPTIONS_
48 SubstrWriter_(
substr buf_,
size_t pos_=0) noexcept : buf(buf_), pos(pos_) { C4_ASSERT(buf.str || !buf.len); }
51 C4_ASSERT(!s.overlaps(buf));
52 if(s.len && pos + s.len <= buf.len)
53 memcpy(buf.str + pos, s.str, s.len);
56 void append(
char c) noexcept
62 void append_n(
char c,
size_t numtimes) noexcept
64 if(numtimes && pos + numtimes < buf.len)
65 memset(buf.str + pos, c, numtimes);
68 size_t slack() const noexcept {
return pos <= buf.len ? buf.len - pos : 0; }
69 size_t excess() const noexcept {
return pos > buf.len ? pos - buf.len : 0; }
71 csubstr curr() const noexcept {
return pos <= buf.
len ? buf.first(pos) : buf; }
73 substr rem() const noexcept {
return pos < buf.
len ? buf.sub(pos) : buf.last(0); }
75 size_t advance(
size_t more) noexcept { pos += more;
return pos; }
81 inline C4_NO_INLINE
csubstr _maybe_add_ellipsis(
substr buf,
size_t len)
83 if C4_UNLIKELY(len > buf.len)
85 const size_t numdots = (buf.len > 3) ? 3 : buf.
len;
86 buf.last(numdots).fill(
'.');
89 return buf.first(len);
97 using type =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
100 struct _dump_directly :
public c4::is_string<typename _remove_cvref<T>::type>
106 template<
class T>
using _remove_cvref_t =
typename _remove_cvref<T>::type;
107 template<
class T>
using _dump_directly_v =
typename _dump_directly<T>::value;
111 if constexpr (_dump_directly<T>::value)
118 size_t len =
to_chars(buf, std::forward<T>(var));
119 return _maybe_add_ellipsis(buf, len);
124 C4_NO_INLINE
auto _to_chars_limited(
substr, T &&var)
125 ->
typename std::enable_if<_dump_directly<T>::value,
csubstr>::type
130 C4_NO_INLINE
auto _to_chars_limited(
substr buf, T &&var)
131 ->
typename std::enable_if< ! _dump_directly<T>::value,
csubstr>::type
133 size_t len =
to_chars(buf, std::forward<T>(var));
134 return _maybe_add_ellipsis(buf, len);
140 template<
class DumpFn>
141 C4_NO_INLINE
void _dump(DumpFn &&dumpfn,
substr,
csubstr fmt)
143 std::forward<DumpFn>(dumpfn)(fmt);
145 template<
class DumpFn,
class Arg,
class ...Args>
146 C4_NO_INLINE
void _dump(DumpFn &&dumpfn,
substr argbuf,
csubstr fmt, Arg
const& arg,
Args const& ...more)
148 size_t pos = fmt.find(
"{}");
150 return std::forward<DumpFn>(dumpfn)(fmt);
151 std::forward<DumpFn>(dumpfn)(fmt.first(pos));
152 std::forward<DumpFn>(dumpfn)(_to_chars_limited(argbuf, arg));
153 _dump(std::forward<DumpFn>(dumpfn), argbuf, fmt.sub(pos + 2), more...);
157 template<
class ...Args>
160 detail::SubstrWriter_ writer(buf);
161 auto dumpfn = [&writer](
csubstr s){ writer.append(s); };
163 _dump(dumpfn, writebuf, fmt, args...);
164 return _maybe_add_ellipsis(buf, writer.pos);
205 template<
class DumpFn>
206 C4_NO_INLINE
size_t location_format(DumpFn &&dumpfn, Location
const& loc);
279 template<
class DumpFn>
281 Location
const &location,
284 size_t num_lines_before = 3,
285 size_t num_lines_after = 0,
286 size_t first_col_highlight = 0,
287 size_t last_col_highlight = 0,
288 size_t maxlen = 80u);
316 template<
class DumpFn>
320 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(Callbacks
const& callbacks, ErrorDataBasic
const& errdata,
const char* msg_);
322 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_basic(ErrorDataBasic
const& errdata,
const char* msg);
324 template<
class ...Args>
331 C4_UNREACHABLE_AFTER_ERR();
334 template<
class ...Args>
338 C4_UNREACHABLE_AFTER_ERR();
371 template<
class DumpFn>
375 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(Callbacks
const& callbacks, ErrorDataParse
const& errdata,
const char *msg);
377 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(ErrorDataParse
const& errdata,
const char *msg);
379 template<
class ...Args>
390 C4_UNREACHABLE_AFTER_ERR();
393 template<
class ...Args>
397 C4_UNREACHABLE_AFTER_ERR();
432 template<
class DumpFn>
437 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(Callbacks
const& callbacks, ErrorDataVisit
const& errdata,
const char *msg);
439 C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(ErrorDataVisit
const& errdata,
const char *msg);
441 template<
class ...Args>
452 C4_UNREACHABLE_AFTER_ERR();
455 template<
class ...Args>
459 C4_UNREACHABLE_AFTER_ERR();
465 #if defined(RYML_WITH_EXCEPTIONS_) || defined(__DOXYGEN__)
477 const char*
what() const noexcept
override {
return msg; }
522 template<
class CharContainer>
527 out->append(s.
str, s.
len);
535 template<
class CharContainer>
540 out->append(s.
str, s.
len);
548 template<
class CharContainer>
553 out->append(s.
str, s.
len);
562 template<
class CharContainer,
class ExceptionT>
570 #endif // RYML_WITH_EXCEPTIONS_
583 # define RYML_ASSERT_BASIC_(cond) RYML_CHECK_BASIC_(cond)
584 # define RYML_ASSERT_BASIC_CB_(cb, cond) RYML_CHECK_BASIC_CB_((cb), cond)
585 # define RYML_ASSERT_BASIC_MSG_(cond, ...) RYML_CHECK_BASIC_CB_MSG_(cond, __VA_ARGS__)
586 # define RYML_ASSERT_BASIC_MSG_CB_(cb, cond, ...) RYML_CHECK_BASIC_MSG_CB_((cb), cond, __VA_ARGS__)
587 # define RYML_ASSERT_PARSE_(cond, ymlloc) RYML_CHECK_PARSE_(cond, (ymlloc))
588 # define RYML_ASSERT_PARSE_CB_(cb, cond, ymlloc) RYML_CHECK_PARSE_CB_((cb), cond, (ymlloc))
589 # define RYML_ASSERT_PARSE_MSG_(cond, ymlloc, ...) RYML_CHECK_PARSE_CB_MSG_(cond, (ymlloc), __VA_ARGS__)
590 # define RYML_ASSERT_PARSE_MSG_CB_(cb, cond, ymlloc, ...) RYML_CHECK_PARSE_MSG_CB_((cb), cond, (ymlloc), __VA_ARGS__)
591 # define RYML_ASSERT_VISIT_(cond, tree, node) RYML_CHECK_VISIT_(cond, (tree), (node))
592 # define RYML_ASSERT_VISIT_CB_(cb, cond, tree, node) RYML_CHECK_VISIT_CB_((cb), cond, (tree), (node))
593 # define RYML_ASSERT_VISIT_MSG_(cond, tree, node, ...) RYML_CHECK_VISIT_CB_MSG_(cond, (tree), (node), __VA_ARGS__)
594 # define RYML_ASSERT_VISIT_MSG_CB_(cb, cond, tree, node, ...) RYML_CHECK_VISIT_MSG_CB_((cb), cond, (tree), (node), __VA_ARGS__)
596 # define RYML_ASSERT_BASIC_(cond)
597 # define RYML_ASSERT_BASIC_CB_(cb, cond)
598 # define RYML_ASSERT_BASIC_MSG_(cond, ...)
599 # define RYML_ASSERT_BASIC_MSG_CB_(cb, cond, ...)
600 # define RYML_ASSERT_PARSE_(cond, ymlloc)
601 # define RYML_ASSERT_PARSE_CB_(cb, cond, ymlloc)
602 # define RYML_ASSERT_PARSE_MSG_(cond, ymlloc, ...)
603 # define RYML_ASSERT_PARSE_MSG_CB_(cb, cond, ymlloc, ...)
604 # define RYML_ASSERT_VISIT_(cont, tree, node)
605 # define RYML_ASSERT_VISIT_CB_(cb, cont, tree, node)
606 # define RYML_ASSERT_VISIT_MSG_(cont, tree, node, ...)
607 # define RYML_ASSERT_VISIT_MSG_CB_(cb, cont, tree, node, ...)
610 #define RYML_ERR_BASIC_(...) \
613 RYML_DEBUG_BREAK(); \
614 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
615 C4_UNREACHABLE_AFTER_ERR(); \
617 #define RYML_ERR_PARSE_(ymlloc, ...) \
620 RYML_DEBUG_BREAK(); \
621 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
622 C4_UNREACHABLE_AFTER_ERR(); \
624 #define RYML_ERR_VISIT_(tree, node, ...) \
627 RYML_DEBUG_BREAK(); \
628 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
629 C4_UNREACHABLE_AFTER_ERR(); \
633 #define RYML_ERR_BASIC_CB_(cb, ...) \
636 RYML_DEBUG_BREAK(); \
637 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
638 C4_UNREACHABLE_AFTER_ERR(); \
640 #define RYML_ERR_PARSE_CB_(cb, ymlloc, ...) \
643 RYML_DEBUG_BREAK(); \
644 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
645 C4_UNREACHABLE_AFTER_ERR(); \
647 #define RYML_ERR_VISIT_CB_(cb, tree, node, ...) \
650 RYML_DEBUG_BREAK(); \
651 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
652 C4_UNREACHABLE_AFTER_ERR(); \
656 #ifndef RYML_SHORT_CHECK_MSG
657 #define RYML_MAYBE_MSG_(cond) ": " #cond
658 #define RYML_MAYBE_MSG_CB_(cond) ": " #cond ": "
660 #define RYML_MAYBE_MSG_(cond)
661 #define RYML_MAYBE_MSG_CB_(cond) ": "
664 #define RYML_CHECK_BASIC_(cond) \
666 if C4_UNLIKELY(!(cond)) \
668 RYML_DEBUG_BREAK(); \
669 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" RYML_MAYBE_MSG_(cond)); \
670 C4_UNREACHABLE_AFTER_ERR(); \
673 #define RYML_CHECK_PARSE_(cond, ymlloc) \
675 if C4_UNLIKELY(!(cond)) \
677 RYML_DEBUG_BREAK(); \
678 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" RYML_MAYBE_MSG_(cond)); \
679 C4_UNREACHABLE_AFTER_ERR(); \
682 #define RYML_CHECK_VISIT_(cond, tree, node) \
684 if C4_UNLIKELY(!(cond)) \
686 RYML_DEBUG_BREAK(); \
687 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" RYML_MAYBE_MSG_(cond)); \
688 C4_UNREACHABLE_AFTER_ERR(); \
693 #define RYML_CHECK_BASIC_CB_(cb, cond) \
695 if C4_UNLIKELY(!(cond)) \
697 RYML_DEBUG_BREAK(); \
698 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" RYML_MAYBE_MSG_(cond)); \
699 C4_UNREACHABLE_AFTER_ERR(); \
702 #define RYML_CHECK_PARSE_CB_(cb, cond, ymlloc) \
704 if C4_UNLIKELY(!(cond)) \
706 RYML_DEBUG_BREAK(); \
707 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" RYML_MAYBE_MSG_(cond)); \
708 C4_UNREACHABLE_AFTER_ERR(); \
711 #define RYML_CHECK_VISIT_CB_(cb, cond, tree, node) \
713 if C4_UNLIKELY(!(cond)) \
715 RYML_DEBUG_BREAK(); \
716 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" RYML_MAYBE_MSG_(cond)); \
717 C4_UNREACHABLE_AFTER_ERR(); \
722 #define RYML_CHECK_BASIC_CB_MSG_(cond, ...) \
724 if C4_UNLIKELY(!(cond)) \
726 RYML_DEBUG_BREAK(); \
727 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" RYML_MAYBE_MSG_CB_(cond) __VA_ARGS__); \
728 C4_UNREACHABLE_AFTER_ERR(); \
731 #define RYML_CHECK_PARSE_CB_MSG_(cond, ymlloc, ...) \
733 if C4_UNLIKELY(!(cond)) \
735 RYML_DEBUG_BREAK(); \
736 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" RYML_MAYBE_MSG_CB_(cond) __VA_ARGS__); \
737 C4_UNREACHABLE_AFTER_ERR(); \
740 #define RYML_CHECK_VISIT_CB_MSG_(cond, tree, node, ...) \
742 if C4_UNLIKELY(!(cond)) \
744 RYML_DEBUG_BREAK(); \
745 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" RYML_MAYBE_MSG_CB_(cond) __VA_ARGS__); \
746 C4_UNREACHABLE_AFTER_ERR(); \
751 #define RYML_CHECK_BASIC_MSG_CB_(cb, cond, ...) \
753 if C4_UNLIKELY(!(cond)) \
755 RYML_DEBUG_BREAK(); \
756 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" RYML_MAYBE_MSG_CB_(cond) __VA_ARGS__); \
757 C4_UNREACHABLE_AFTER_ERR(); \
760 #define RYML_CHECK_PARSE_MSG_CB_(cb, cond, ymlloc, ...) \
762 if C4_UNLIKELY(!(cond)) \
764 RYML_DEBUG_BREAK(); \
765 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" RYML_MAYBE_MSG_CB_(cond) __VA_ARGS__); \
766 C4_UNREACHABLE_AFTER_ERR(); \
769 #define RYML_CHECK_VISIT_MSG_CB_(cb, cond, tree, node, ...) \
771 if C4_UNLIKELY(!(cond)) \
773 RYML_DEBUG_BREAK(); \
774 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" RYML_MAYBE_MSG_CB_(cond) __VA_ARGS__); \
775 C4_UNREACHABLE_AFTER_ERR(); \
size_t to_chars(substr buf, escaped_scalar e)
formatting implementation to escape a scalar with escape_scalar()
void format_exc(CharContainer *out, ExceptionBasic const &exc)
Format a basic exception to an existing char container.
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...
char msg[RYML_ERRMSG_SIZE]
the reported error message, without location indication.
C * str
a restricted pointer to the first character of the substring
A c-style callbacks class to customize behavior on errors or allocation.
Exception thrown by the default visit error implementation.
Exception thrown by the default basic error implementation.
Location ymlloc
location in the YAML source buffer where the error was detected.
ErrorDataVisit errdata_visit
void err_parse(ErrorDataParse const &errdata, const char *msg)
trigger a parse error to its respective handler, with a non-formatted error message.
void err_visit(ErrorDataVisit const &errdata, const char *msg)
trigger a visit error to its respective handler, with a non-formatted error message.
csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
Location cpploc
location in the C++ source file where the error was detected.
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...
Common utilities and infrastructure used by ryml.
ErrorDataBasic errdata_basic
error data
#define RYML_ERRMSG_SIZE
size for the error message buffer
void err_basic(ErrorDataBasic const &errdata, const char *msg)
trigger a basic error to its respective handler, with a non-formatted error message.
const char * what() const noexcept override
a traits class to mark a type as a string type, meaning c4::to_csubstr() can be used directly instead...
void * m_user_data
data to be forwarded in every call to a callback
pfn_error_parse m_error_parse
a pointer to a parse error handler function
Lightweight generic type-safe wrappers for converting individual values to/from strings.
csubstr to_csubstr(const char(&s)[N]) noexcept
#define RYML_NOEXCEPT
Conditionally expands to noexcept when RYML_USE_ASSERT is 0 and is empty otherwise.
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
pfn_error_basic m_error_basic
a pointer to a basic error handler function
size_t len
the length of the substring
#define RYML_LOGBUF_SIZE
size for the buffer used to format individual values to string while preparing an error message...
pfn_error_visit m_error_visit
a pointer to a visit error handler function
Exception thrown by the default parse error implementation.
Callbacks const & get_callbacks()
get the global callbacks
size_t location_format(DumpFn &&dumpfn, Location const &loc)
generic formatting of a location
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...
ErrorDataParse errdata_parse
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...