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; }
81inline 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;
100struct _dump_directly :
public c4::is_string<typename _remove_cvref<T>::type>
106template<
class T>
using _remove_cvref_t =
typename _remove_cvref<T>::type;
107template<
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);
124C4_NO_INLINE
auto _to_chars_limited(
substr, T &&var)
125 ->
typename std::enable_if<_dump_directly<T>::value,
csubstr>::type
130C4_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);
140template<
class DumpFn>
143 std::forward<DumpFn>(dumpfn)(fmt);
145template<
class DumpFn,
class Arg,
class ...Args>
146C4_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...);
157template<
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);
205template<
class DumpFn>
279template<
class DumpFn>
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);
316template<
class DumpFn>
324template<
class ...Args>
331 C4_UNREACHABLE_AFTER_ERR();
334template<
class ...Args>
338 C4_UNREACHABLE_AFTER_ERR();
371template<
class DumpFn>
375C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(Callbacks
const& callbacks, ErrorDataParse
const& errdata,
const char *msg);
377C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(ErrorDataParse
const& errdata,
const char *msg);
379template<
class ...Args>
390 C4_UNREACHABLE_AFTER_ERR();
393template<
class ...Args>
397 C4_UNREACHABLE_AFTER_ERR();
432template<
class DumpFn>
437C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(Callbacks
const& callbacks, ErrorDataVisit
const& errdata,
const char *msg);
439C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(ErrorDataVisit
const& errdata,
const char *msg);
441template<
class ...Args>
452 C4_UNREACHABLE_AFTER_ERR();
455template<
class ...Args>
459 C4_UNREACHABLE_AFTER_ERR();
465#if defined(RYML_WITH_EXCEPTIONS_) || defined(__DOXYGEN__)
477 const char*
what() const noexcept
override {
return msg; }
522template<
class CharContainer>
527 out->append(s.
str, s.
len);
535template<
class CharContainer>
540 out->append(s.
str, s.
len);
548template<
class CharContainer>
553 out->append(s.
str, s.
len);
562template<
class CharContainer,
class ExceptionT>
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(); \
Lightweight generic type-safe wrappers for converting individual values to/from strings.
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....
#define RYML_NOEXCEPT
Conditionally expands to noexcept when RYML_USE_ASSERT is 0 and is empty otherwise.
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(const char(&s)[N]) noexcept
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
size_t to_chars(substr buf, escaped_scalar e)
formatting implementation to escape a scalar with escape_scalar()
size_t len
the length of the substring
size_t find(const C c, size_t start_pos=0) const
C * str
a restricted pointer to the first character of the substring
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.
const char * what() const noexcept override
ErrorDataBasic errdata_basic
error data
ExceptionBasic(csubstr msg, ErrorDataBasic const &errdata_) noexcept
char msg[RYML_ERRMSG_SIZE]
the reported error message, without location indication.
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
holds a source or yaml file position, for example when an error is detected; See also location_format...