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; }
84inline 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;
103struct _dump_directly :
public c4::is_string<typename _remove_cvref<T>::type>
109template<
class T>
using _remove_cvref_t =
typename _remove_cvref<T>::type;
110template<
class T>
using _dump_directly_v =
typename _dump_directly<T>::value;
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);
127C4_NO_INLINE
auto _to_chars_limited(
substr, T &&var)
128 ->
typename std::enable_if<_dump_directly<T>::value,
csubstr>::type
133C4_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);
143template<
class DumpFn>
146 std::forward<DumpFn>(dumpfn)(fmt);
148template<
class DumpFn,
class Arg,
class ...Args>
149C4_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...);
160template<
class ...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);
208template<
class DumpFn>
282template<
class DumpFn>
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);
319template<
class DumpFn>
327template<
class ...Args>
334 C4_UNREACHABLE_AFTER_ERR();
337template<
class ...Args>
341 C4_UNREACHABLE_AFTER_ERR();
374template<
class DumpFn>
378C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(Callbacks
const& callbacks, ErrorDataParse
const& errdata,
const char *msg);
380C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_parse(ErrorDataParse
const& errdata,
const char *msg);
382template<
class ...Args>
393 C4_UNREACHABLE_AFTER_ERR();
396template<
class ...Args>
400 C4_UNREACHABLE_AFTER_ERR();
435template<
class DumpFn>
440C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(Callbacks
const& callbacks, ErrorDataVisit
const& errdata,
const char *msg);
442C4_NORETURN
RYML_EXPORT C4_NO_INLINE
void err_visit(ErrorDataVisit
const& errdata,
const char *msg);
444template<
class ...Args>
455 C4_UNREACHABLE_AFTER_ERR();
458template<
class ...Args>
462 C4_UNREACHABLE_AFTER_ERR();
468#if defined(_RYML_WITH_EXCEPTIONS) || defined(__DOXYGEN__)
480 const char*
what() const noexcept
override {
return msg; }
525template<
class CharContainer>
530 out->append(s.
str, s.
len);
538template<
class CharContainer>
543 out->append(s.
str, s.
len);
551template<
class CharContainer>
556 out->append(s.
str, s.
len);
565template<
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(const char(&s)[N]) noexcept
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
a CRTP base providing read-only methods for ConstNodeRef and NodeRef
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()
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
size_t len
the length of the substring
size_t find(const C c, size_t start_pos=0) const
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
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...