Improve error annotations & code docs

This commit is contained in:
Joao Paulo Magalhaes
2024-04-12 18:24:51 +01:00
parent 8a72a97025
commit a2527b5429
15 changed files with 1231 additions and 601 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@ namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702/*unreachable code*/) // on the call to the unreachable macro
namespace {
Callbacks s_default_callbacks;
@@ -39,7 +40,7 @@ void report_error_impl(const char* msg, size_t length, Location loc, FILE *f)
fflush(f);
}
void error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
[[noreturn]] void error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
{
report_error_impl(msg, length, loc, nullptr);
#ifdef RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
@@ -89,7 +90,7 @@ Callbacks::Callbacks(void *user_data, pfn_allocate alloc_, pfn_free free_, pfn_e
#ifndef RYML_NO_DEFAULT_CALLBACKS
m_allocate(alloc_ ? alloc_ : allocate_impl),
m_free(free_ ? free_ : free_impl),
m_error(error_ ? error_ : error_impl)
m_error((error_ ? error_ : error_impl))
#else
m_allocate(alloc_),
m_free(free_),
@@ -117,11 +118,24 @@ void reset_callbacks()
set_callbacks(Callbacks());
}
void error(const char *msg, size_t msg_len, Location loc)
// the [[noreturn]] attribute needs to be here as well (UB otherwise)
// https://en.cppreference.com/w/cpp/language/attributes/noreturn
[[noreturn]] void error(Callbacks const& cb, const char *msg, size_t msg_len, Location loc)
{
s_default_callbacks.m_error(msg, msg_len, loc, s_default_callbacks.m_user_data);
cb.m_error(msg, msg_len, loc, cb.m_user_data);
abort(); // call abort in case the error callback didn't interrupt execution
C4_UNREACHABLE();
}
// the [[noreturn]] attribute needs to be here as well (UB otherwise)
// see https://en.cppreference.com/w/cpp/language/attributes/noreturn
[[noreturn]] void error(const char *msg, size_t msg_len, Location loc)
{
error(s_default_callbacks, msg, msg_len, loc);
C4_UNREACHABLE();
}
C4_SUPPRESS_WARNING_MSVC_POP
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace yml

View File

@@ -1,18 +1,127 @@
#ifndef _C4_YML_COMMON_HPP_
#define _C4_YML_COMMON_HPP_
/** @file common.hpp Common utilities and infrastructure used by ryml. */
#include <cstddef>
#include <c4/substr.hpp>
#include <c4/yml/export.hpp>
#ifndef RYML_USE_ASSERT
/** define this macro with a boolean value to force enable/disable
assertions. This causes a slowdown of the code.*/
# define RYML_USE_ASSERT C4_USE_ASSERT
//-----------------------------------------------------------------------------
// Specify groups to have a predefined topic order in doxygen:
/** @defgroup doc_quickstart Quickstart
*
* Example code for every feature.
*/
/** @defgroup doc_parse Parse utilities
* @see sample::sample_parse_in_place
* @see sample::sample_parse_in_arena
* @see sample::sample_parse_file
* @see sample::sample_parse_reuse_tree
* @see sample::sample_parse_reuse_parser
* @see sample::sample_parse_reuse_tree_and_parser
* @see sample::sample_location_tracking
*/
/** @defgroup doc_emit Emit utilities
*
* Utilities to emit YAML and JSON, either to a memory buffer or to a
* file or ostream-like class.
*
* @see sample::sample_emit_to_container
* @see sample::sample_emit_to_stream
* @see sample::sample_emit_to_file
* @see sample::sample_emit_nested_node
* @see sample::sample_emit_style
*/
/** @defgroup doc_node_type Node types
*/
/** @defgroup doc_tree Tree utilities
* @see sample::sample_quick_overview
* @see sample::sample_iterate_trees
* @see sample::sample_create_trees
* @see sample::sample_tree_arena
*
* @see sample::sample_static_trees
* @see sample::sample_location_tracking
*
* @see sample::sample_docs
* @see sample::sample_anchors_and_aliases
* @see sample::sample_tags
*/
/** @defgroup doc_node_classes Node classes
*
* High-level node classes.
*
* @see sample::sample_quick_overview
* @see sample::sample_iterate_trees
* @see sample::sample_create_trees
* @see sample::sample_tree_arena
*/
/** @defgroup doc_callbacks Callbacks for errors and allocation
*
* Functions called by ryml to allocate/free memory and to report
* errors.
*
* @see sample::sample_error_handler
* @see sample::sample_global_allocator
* @see sample::sample_per_tree_allocator
*/
/** @defgroup doc_tag_utils Tag utilities
* @see sample::sample_tags
*/
/** @defgroup doc_preprocessors Preprocessors
*
* Functions for preprocessing YAML prior to parsing.
*/
//-----------------------------------------------------------------------------
// document macros for doxygen
#ifdef __DOXYGEN__ // defined in Doxyfile::PREDEFINED
/** define this macro with a boolean value to enable/disable
* assertions to check preconditions and assumptions throughout the
* codebase; this causes a slowdown of the code, and larger code
* size. By default, this macro is defined unless NDEBUG is defined
* (see C4_USE_ASSERT); as a result, by default this macro is truthy
* only in debug builds. */
# define RYML_USE_ASSERT
/** (Undefined by default) Define this macro to disable ryml's default
* implementation of the callback functions; see @ref c4::yml::Callbacks */
# define RYML_NO_DEFAULT_CALLBACKS
/** (Undefined by default) When this macro is defined (and
* @ref RYML_NO_DEFAULT_CALLBACKS is not defined), the default error
* handler will throw C++ exceptions of type `std::runtime_error`. */
# define RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
/** Conditionally expands to `noexcept` when @ref RYML_USE_ASSERT is 0 and
* is empty otherwise. The user is unable to override this macro. */
# define RYML_NOEXCEPT
#endif
//-----------------------------------------------------------------------------
/** @cond dev*/
#ifndef RYML_USE_ASSERT
# define RYML_USE_ASSERT C4_USE_ASSERT
#endif
#if RYML_USE_ASSERT
# define RYML_ASSERT(cond) RYML_CHECK(cond)
# define RYML_ASSERT_MSG(cond, msg) RYML_CHECK_MSG(cond, msg)
@@ -25,6 +134,28 @@
# define RYML_NOEXCEPT noexcept
#endif
#define RYML_DEPRECATED(msg) C4_DEPRECATED(msg)
#define RYML_CHECK(cond) \
do { \
if(C4_UNLIKELY(!(cond))) \
{ \
RYML_DEBUG_BREAK() \
c4::yml::error("check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#define RYML_CHECK_MSG(cond, msg) \
do \
{ \
if(C4_UNLIKELY(!(cond))) \
{ \
RYML_DEBUG_BREAK() \
c4::yml::error(msg ": check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
# define RYML_DEBUG_BREAK() \
@@ -39,35 +170,7 @@
#endif
#define RYML_CHECK(cond) \
do { \
if(!(cond)) \
{ \
RYML_DEBUG_BREAK() \
c4::yml::error("check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
} \
} while(0)
#define RYML_CHECK_MSG(cond, msg) \
do \
{ \
if(!(cond)) \
{ \
RYML_DEBUG_BREAK() \
c4::yml::error(msg ": check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
} \
} while(0)
#if C4_CPP >= 14
# define RYML_DEPRECATED(msg) [[deprecated(msg)]]
#else
# if defined(_MSC_VER)
# define RYML_DEPRECATED(msg) __declspec(deprecated(msg))
# else // defined(__GNUC__) || defined(__clang__)
# define RYML_DEPRECATED(msg) __attribute__((deprecated(msg)))
# endif
#endif
/** @endcond */
//-----------------------------------------------------------------------------
@@ -127,46 +230,58 @@ struct RYML_EXPORT Location : public LineCol
//-----------------------------------------------------------------------------
/** the type of the function used to report errors. This function must
* interrupt execution, either by raising an exception or calling
* std::abort().
/** @addtogroup doc_callbacks
*
* @warning the error callback must never return: it must either abort
* or throw an exception. Otherwise, the parser will enter into an
* infinite loop, or the program may crash. */
using pfn_error = void (*)(const char* msg, size_t msg_len, Location location, void *user_data);
/** the type of the function used to allocate memory */
* @{ */
struct Callbacks;
/** set the global callbacks for the library; after a call to this
* function, these callbacks will be used by newly created objects
* (unless they are copying older objects with different
* callbacks). If @ref RYML_NO_DEFAULT_CALLBACKS is defined, it is
* mandatory to call this function prior to using any other library
* facility.
*
* @warning This function is NOT thread-safe.
*
* @warning the error callback must never return: see @ref pfn_error
* for more details */
RYML_EXPORT void set_callbacks(Callbacks const& c);
/** get the global callbacks
* @warning This function is not thread-safe. */
RYML_EXPORT Callbacks const& get_callbacks();
/** set the global callbacks back to their defaults ()
* @warning This function is not thread-safe. */
RYML_EXPORT void reset_callbacks();
/** the type of the function used to report errors
*
* @warning When given by the user, this function MUST interrupt
* execution, typically by either throwing an exception, or using
* `std::longjmp()` ([see
* documentation](https://en.cppreference.com/w/cpp/utility/program/setjmp))
* or by calling `std::abort()`. If the function returned, the parser
* would enter into an infinite loop, or the program may crash. */
using pfn_error = void (*) (const char* msg, size_t msg_len, Location location, void *user_data);
/** the type of the function used to allocate memory; ryml will only
* allocate memory through this callback. */
using pfn_allocate = void* (*)(size_t len, void* hint, void *user_data);
/** the type of the function used to free memory */
/** the type of the function used to free memory; ryml will only free
* memory through this callback. */
using pfn_free = void (*)(void* mem, size_t size, void *user_data);
/** trigger an error: call the current error callback. */
RYML_EXPORT void error(const char *msg, size_t msg_len, Location loc);
/** @overload error */
inline void error(const char *msg, size_t msg_len)
{
error(msg, msg_len, Location{});
}
/** @overload error */
template<size_t N>
inline void error(const char (&msg)[N], Location loc)
{
error(msg, N-1, loc);
}
/** @overload error */
template<size_t N>
inline void error(const char (&msg)[N])
{
error(msg, N-1, Location{});
}
//-----------------------------------------------------------------------------
/** a c-style callbacks class
*
* @warning the error callback must never return: it must either abort
* or throw an exception. Otherwise, the parser will enter into an
* infinite loop, or the program may crash. */
/** a c-style callbacks class. Can be used globally by the library
* and/or locally by @ref Tree and @ref Parser objects. */
struct RYML_EXPORT Callbacks
{
void * m_user_data;
@@ -174,8 +289,32 @@ struct RYML_EXPORT Callbacks
pfn_free m_free;
pfn_error m_error;
/** Construct an object with the default callbacks. If
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, the object will have null
* members.*/
Callbacks();
Callbacks(void *user_data, pfn_allocate alloc, pfn_free free, pfn_error error_);
/** Construct an object with the given callbacks.
*
* @param user_data Data to be forwarded in every call to a callback.
*
* @param alloc A pointer to an allocate function. Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default
* alloc implementation.
*
* @param free A pointer to a free function. Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default free
* implementation.
*
* @param error A pointer to an error function, which must never
* return (see @ref pfn_error). Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default
* error implementation.
*/
Callbacks(void *user_data, pfn_allocate alloc, pfn_free free, pfn_error error);
bool operator!= (Callbacks const& that) const { return !operator==(that); }
bool operator== (Callbacks const& that) const
@@ -187,24 +326,44 @@ struct RYML_EXPORT Callbacks
}
};
/** set the global callbacks.
*
* @warning the error callback must never return: it must either abort
* or throw an exception. Otherwise, the parser will enter into an
* infinite loop, or the program may crash. */
RYML_EXPORT void set_callbacks(Callbacks const& c);
/// get the global callbacks
RYML_EXPORT Callbacks const& get_callbacks();
/// set the global callbacks back to their defaults
RYML_EXPORT void reset_callbacks();
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
// BEWARE! MSVC requires that [[noreturn]] appears before RYML_EXPORT
[[noreturn]] RYML_EXPORT void error(Callbacks const& cb, const char *msg, size_t msg_len, Location loc);
[[noreturn]] RYML_EXPORT void error(const char *msg, size_t msg_len, Location loc);
[[noreturn]] inline void error(const char *msg, size_t msg_len)
{
error(msg, msg_len, Location{});
}
template<size_t N>
[[noreturn]] inline void error(const char (&msg)[N], Location loc)
{
error(msg, N-1, loc);
}
template<size_t N>
[[noreturn]] inline void error(const char (&msg)[N])
{
error(msg, N-1, Location{});
}
#define _RYML_CB_ERR(cb, msg_literal) \
do \
{ \
const char msg[] = msg_literal; \
RYML_DEBUG_BREAK() \
(cb).m_error(msg, sizeof(msg), c4::yml::Location(__FILE__, 0, __LINE__, 0), (cb).m_user_data); \
c4::yml::error((cb), \
msg, sizeof(msg), \
c4::yml::Location(__FILE__, 0, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} while(0)
#define _RYML_CB_CHECK(cb, cond) \
do \
@@ -213,7 +372,10 @@ do \
{ \
const char msg[] = "check failed: " #cond; \
RYML_DEBUG_BREAK() \
(cb).m_error(msg, sizeof(msg), c4::yml::Location(__FILE__, 0, __LINE__, 0), (cb).m_user_data); \
c4::yml::error((cb), \
msg, sizeof(msg), \
c4::yml::Location(__FILE__, 0, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#define _RYML_CB_ALLOC_HINT(cb, T, num, hint) (T*) (cb).m_allocate((num) * sizeof(T), (hint), (cb).m_user_data)
@@ -225,7 +387,6 @@ do \
} while(0)
namespace detail {
template<int8_t signedval, uint8_t unsignedval>
struct _charconstant_t

View File

@@ -5,6 +5,8 @@
#include "c4/yml/emit.hpp"
#endif
/** @file emit.def.hpp Definitions for emit functions. */
namespace c4 {
namespace yml {
@@ -16,6 +18,8 @@ substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, size_t id, bool
_RYML_CB_ASSERT(t.callbacks(), id == NONE);
return {};
}
if(id == NONE)
id = t.root_id();
_RYML_CB_CHECK(t.callbacks(), id < t.capacity());
m_tree = &t;
if(type == EMIT_YAML)
@@ -24,6 +28,7 @@ substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, size_t id, bool
_do_visit_json(id);
else
_RYML_CB_ERR(m_tree->callbacks(), "unknown emit type");
m_tree = nullptr;
return this->Writer::_get(error_on_excess);
}
@@ -269,13 +274,15 @@ void Emitter<Writer>::_do_visit_flow_sl(size_t node, size_t ilevel)
}
}
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702) // unreachable error, triggered by flow_ml not implemented
template<class Writer>
void Emitter<Writer>::_do_visit_flow_ml(size_t id, size_t ilevel, size_t do_indent)
{
C4_UNUSED(id);
C4_UNUSED(ilevel);
C4_UNUSED(do_indent);
RYML_CHECK(false/*not implemented*/);
c4::yml::error("not implemented");
}
template<class Writer>
@@ -452,6 +459,9 @@ void Emitter<Writer>::_do_visit_block(size_t node, size_t ilevel, size_t do_inde
_do_visit_block_container(node, next_level, do_indent);
}
C4_SUPPRESS_WARNING_MSVC_POP
template<class Writer>
void Emitter<Writer>::_do_visit_json(size_t id)
{

View File

@@ -1,6 +1,8 @@
#ifndef _C4_YML_EMIT_HPP_
#define _C4_YML_EMIT_HPP_
/** @file emit.hpp Utilities to emit YAML and JSON. */
#ifndef _C4_YML_WRITER_HPP_
#include "./writer.hpp"
#endif
@@ -13,12 +15,11 @@
#include "./node.hpp"
#endif
#define RYML_DEPRECATE_EMIT \
RYML_DEPRECATED("use emit_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
#ifdef emit
#error "emit is defined, likely from a Qt include. This will cause a compilation error. See https://github.com/biojppm/rapidyaml/issues/120"
#endif
#define RYML_DEPRECATE_EMIT \
RYML_DEPRECATED("use emit_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
#define RYML_DEPRECATE_EMITRS \
RYML_DEPRECATED("use emitrs_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
@@ -30,50 +31,58 @@
namespace c4 {
namespace yml {
template<class Writer> class Emitter;
/** @addtogroup doc_emit
*
* @{
*/
// fwd declarations
template<class Writer> class Emitter;
template<class OStream>
using EmitterOStream = Emitter<WriterOStream<OStream>>;
using EmitterFile = Emitter<WriterFile>;
using EmitterBuf = Emitter<WriterBuf>;
/** Specifies the type of content to emit */
typedef enum {
EMIT_YAML = 0,
EMIT_JSON = 1
EMIT_YAML = 0, ///< emit YAML
EMIT_JSON = 1 ///< emit JSON
} EmitType_e;
/** mark a tree or node to be emitted as json */
struct as_json
{
Tree const* tree;
size_t node;
as_json(Tree const& t) : tree(&t), node(t.empty() ? NONE : t.root_id()) {}
as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
as_json(ConstNodeRef const& n) : tree(n.tree()), node(n.id()) {}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A stateful emitter, for use with a writer such as @ref WriterBuf,
* @ref WriterFile, or @ref WriterOStream */
template<class Writer>
class Emitter : public Writer
{
public:
using Writer::Writer;
/** Construct the emitter and its internal Writer state. Every
* parameter is forwarded to the constructor of the writer. */
template<class ...Args>
Emitter(Args &&...args) : Writer(std::forward<Args>(args)...), m_tree() {}
/** emit!
*
* When writing to a buffer, returns a substr of the emitted YAML.
* If the given buffer has insufficient space, the returned span will
* be null and its size will be the needed space. No writes are done
* after the end of the buffer.
* If the given buffer has insufficient space, the returned substr
* will be null and its size will be the needed space. Whatever
* the size of the buffer, it is guaranteed that no writes are
* done past its end.
*
* When writing to a file, the returned substr will be null, but its
* length will be set to the number of bytes written. */
* length will be set to the number of bytes written.
*
* @param type specify what to emit
* @param t the tree to emit
* @param id the id of the node to emit
* @param error_on_excess when true, an error is raised when the
* output buffer is too small for the emitted YAML/JSON
* */
substr emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);
/** emit starting at the root node */
substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true);
@@ -132,6 +141,12 @@ private:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_file Emit to file
*
* @{
*/
/** emit YAML to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_yaml(Tree const& t, size_t id, FILE *f)
@@ -139,11 +154,6 @@ inline size_t emit_yaml(Tree const& t, size_t id, FILE *f)
EmitterFile em(f);
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
}
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, size_t id, FILE *f)
{
return emit_yaml(t, id, f);
}
/** emit JSON to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_json(Tree const& t, size_t id, FILE *f)
@@ -161,11 +171,6 @@ inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
EmitterFile em(f);
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
}
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
{
return emit_yaml(t, f);
}
/** emit JSON to the given file. A null file defaults to stdout.
* Return the number of bytes written.
* @overload */
@@ -184,11 +189,6 @@ inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
EmitterFile em(f);
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
}
RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
{
return emit_yaml(r, f);
}
/** emit JSON to the given file. A null file defaults to stdout.
* Return the number of bytes written.
* @overload */
@@ -198,9 +198,34 @@ inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_ostream Emit to an STL-like ostream
*
* @{
*/
/** mark a tree or node to be emitted as json when using @ref operator<< . For example:
*
* ```cpp
* Tree t = parse_in_arena("{foo: bar}");
* std::cout << t; // emits YAML
* std::cout << as_json(t); // emits JSON
* ```
*
* @see @ref operator<< */
struct as_json
{
Tree const* tree;
size_t node;
as_json(Tree const& t) : tree(&t), node(t.empty() ? NONE : t.root_id()) {}
as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
as_json(ConstNodeRef const& n) : tree(n.tree()), node(n.id()) {}
};
/** emit YAML to an STL-like ostream */
template<class OStream>
inline OStream& operator<< (OStream& s, Tree const& t)
@@ -229,9 +254,15 @@ inline OStream& operator<< (OStream& s, as_json const& j)
return s;
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_buffer Emit to memory buffer
*
* @{
*/
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
@@ -241,11 +272,6 @@ inline substr emit_yaml(Tree const& t, size_t id, substr buf, bool error_on_exce
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, id, buf, error_on_excess);
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @overload */
@@ -264,11 +290,6 @@ inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, t, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, buf, error_on_excess);
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @overload */
@@ -288,11 +309,6 @@ inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, r, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
return emit_yaml(r, buf, error_on_excess);
}
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @overload
@@ -306,7 +322,7 @@ inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=
//-----------------------------------------------------------------------------
/** emit+resize: emit YAML to the given std::string/std::vector-like
/** emit+resize: emit YAML to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, size_t id, CharOwningContainer * cont)
@@ -321,13 +337,7 @@ substr emitrs_yaml(Tree const& t, size_t id, CharOwningContainer * cont)
}
return ret;
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
{
return emitrs_yaml(t, id, cont);
}
/** emit+resize: emit JSON to the given std::string/std::vector-like
/** emit+resize: emit JSON to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
@@ -344,7 +354,7 @@ substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
}
/** emit+resize: emit YAML to the given std::string/std::vector-like
/** emit+resize: emit YAML to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(Tree const& t, size_t id)
@@ -353,15 +363,7 @@ CharOwningContainer emitrs_yaml(Tree const& t, size_t id)
emitrs_yaml(t, id, &c);
return c;
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, size_t id)
{
CharOwningContainer c;
emitrs_yaml(t, id, &c);
return c;
}
/** emit+resize: emit JSON to the given std::string/std::vector-like
/** emit+resize: emit JSON to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t, size_t id)
@@ -372,7 +374,7 @@ CharOwningContainer emitrs_json(Tree const& t, size_t id)
}
/** emit+resize: YAML to the given std::string/std::vector-like
/** emit+resize: YAML to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, CharOwningContainer * cont)
@@ -381,13 +383,7 @@ substr emitrs_yaml(Tree const& t, CharOwningContainer * cont)
return {};
return emitrs_yaml(t, t.root_id(), cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
{
return emitrs_yaml(t, cont);
}
/** emit+resize: JSON to the given std::string/std::vector-like
/** emit+resize: JSON to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, CharOwningContainer * cont)
@@ -398,7 +394,7 @@ substr emitrs_json(Tree const& t, CharOwningContainer * cont)
}
/** emit+resize: YAML to the given std::string/std::vector-like container,
/** emit+resize: YAML to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(Tree const& t)
@@ -409,13 +405,7 @@ CharOwningContainer emitrs_yaml(Tree const& t)
emitrs_yaml(t, t.root_id(), &c);
return c;
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
{
return emitrs_yaml<CharOwningContainer>(t);
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
/** emit+resize: JSON to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t)
@@ -428,7 +418,7 @@ CharOwningContainer emitrs_json(Tree const& t)
}
/** emit+resize: YAML to the given std::string/std::vector-like container,
/** emit+resize: YAML to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont)
@@ -436,13 +426,7 @@ substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont)
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_yaml(*n.tree(), n.id(), cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
{
return emitrs_yaml(n, cont);
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
/** emit+resize: JSON to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)
@@ -452,7 +436,7 @@ substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)
}
/** emit+resize: YAML to the given std::string/std::vector-like container,
/** emit+resize: YAML to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted YAML. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(ConstNodeRef const& n)
@@ -462,13 +446,7 @@ CharOwningContainer emitrs_yaml(ConstNodeRef const& n)
emitrs_yaml(*n.tree(), n.id(), &c);
return c;
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
{
return emitrs_yaml<CharOwningContainer>(n);
}
/** emit+resize: JSON to the given std::string/std::vector-like container,
/** emit+resize: JSON to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted JSON. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(ConstNodeRef const& n)
@@ -479,6 +457,72 @@ CharOwningContainer emitrs_json(ConstNodeRef const& n)
return c;
}
/** @} */
//-----------------------------------------------------------------------------
/** @cond dev */
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, size_t id, FILE *f)
{
return emit_yaml(t, id, f);
}
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
{
return emit_yaml(t, f);
}
RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
{
return emit_yaml(r, f);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, id, buf, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, buf, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
return emit_yaml(r, buf, error_on_excess);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
{
return emitrs_yaml(t, id, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, size_t id)
{
return emitrs_yaml<CharOwningContainer>(t, id);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
{
return emitrs_yaml(t, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
{
return emitrs_yaml<CharOwningContainer>(t);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
{
return emitrs_yaml(n, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
{
return emitrs_yaml<CharOwningContainer>(n);
}
/** @endcond */
} // namespace yml
} // namespace c4

View File

@@ -1,8 +1,7 @@
#ifndef _C4_YML_NODE_HPP_
#define _C4_YML_NODE_HPP_
/** @file node.hpp
* @see NodeRef */
/** @file node.hpp Node classes */
#include <cstddef>
@@ -26,6 +25,16 @@
namespace c4 {
namespace yml {
/** @addtogroup doc_node_classes
*
* @{
*/
/** @defgroup doc_serialization_helpers Serialization helpers
*
* @{
*/
template<class K> struct Key { K & k; };
template<> struct Key<fmt::const_base64_wrapper> { fmt::const_base64_wrapper wrapper; };
template<> struct Key<fmt::base64_wrapper> { fmt::base64_wrapper wrapper; };
@@ -44,6 +53,8 @@ template<class T>
typename std::enable_if< std::is_floating_point<T>::value, bool>::type
read(NodeRef const& n, T *v);
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
@@ -53,10 +64,12 @@ read(NodeRef const& n, T *v);
class NodeRef;
class ConstNodeRef;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @cond dev */
namespace detail {
template<class NodeRefType>
@@ -145,14 +158,22 @@ bool _visit_stacked(NodeRefType &node, Visitor fn, size_t indentation_level, boo
return false;
}
template<class Impl, class ConstImpl>
struct RoNodeMethods;
} // detail
/** @endcond */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a CRTP base for read-only node methods */
/** a CRTP base providing read-only methods for @ref ConstNodeRef and @ref NodeRef */
template<class Impl, class ConstImpl>
struct RoNodeMethods
struct detail::RoNodeMethods
{
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wcast-align")
/** @cond dev */
// helper CRTP macros, undefined at the end
#define tree_ ((ConstImpl const* C4_RESTRICT)this)->m_tree
#define id_ ((ConstImpl const* C4_RESTRICT)this)->m_id
@@ -163,8 +184,9 @@ struct RoNodeMethods
#define _C4RR() \
RYML_ASSERT(tree_ != nullptr); \
_RYML_CB_ASSERT(tree_->m_callbacks, id_ != NONE); \
_RYML_CB_ASSERT(tree_->m_callbacks, (((Impl const* C4_RESTRICT)this)->readable()));
_RYML_CB_ASSERT(tree_->m_callbacks, (((Impl const* C4_RESTRICT)this)->readable()))
#define _C4_IF_MUTABLE(ty) typename std::enable_if<!std::is_same<U, ConstImpl>::value, ty>::type
/** @endcond */
public:
@@ -177,7 +199,7 @@ public:
template<class U=Impl>
C4_ALWAYS_INLINE auto get() RYML_NOEXCEPT -> _C4_IF_MUTABLE(NodeData*) { return ((Impl const*)this)->readable() ? tree__->get(id__) : nullptr; }
C4_ALWAYS_INLINE NodeType type() const RYML_NOEXCEPT { _C4RR(); return tree_->type(id_); }
C4_ALWAYS_INLINE NodeType type() const RYML_NOEXCEPT { _C4RR(); return tree_->type(id_); }
C4_ALWAYS_INLINE const char* type_str() const RYML_NOEXCEPT { _C4RR(); return tree_->type_str(id_); }
C4_ALWAYS_INLINE csubstr key() const RYML_NOEXCEPT { _C4RR(); return tree_->key(id_); }
@@ -203,33 +225,33 @@ public:
/** @name node property predicates */
/** @{ */
C4_ALWAYS_INLINE bool empty() const RYML_NOEXCEPT { _C4RR(); return tree_->empty(id_); }
C4_ALWAYS_INLINE bool is_stream() const RYML_NOEXCEPT { _C4RR(); return tree_->is_stream(id_); }
C4_ALWAYS_INLINE bool is_doc() const RYML_NOEXCEPT { _C4RR(); return tree_->is_doc(id_); }
C4_ALWAYS_INLINE bool is_container() const RYML_NOEXCEPT { _C4RR(); return tree_->is_container(id_); }
C4_ALWAYS_INLINE bool is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->is_map(id_); }
C4_ALWAYS_INLINE bool is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->is_seq(id_); }
C4_ALWAYS_INLINE bool has_val() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val(id_); }
C4_ALWAYS_INLINE bool has_key() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key(id_); }
C4_ALWAYS_INLINE bool is_val() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val(id_); }
C4_ALWAYS_INLINE bool is_keyval() const RYML_NOEXCEPT { _C4RR(); return tree_->is_keyval(id_); }
C4_ALWAYS_INLINE bool has_key_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_tag(id_); }
C4_ALWAYS_INLINE bool has_val_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_tag(id_); }
C4_ALWAYS_INLINE bool has_key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_anchor(id_); }
C4_ALWAYS_INLINE bool is_key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_anchor(id_); }
C4_ALWAYS_INLINE bool has_val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_anchor(id_); }
C4_ALWAYS_INLINE bool is_val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_anchor(id_); }
C4_ALWAYS_INLINE bool has_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_anchor(id_); }
C4_ALWAYS_INLINE bool is_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->is_anchor(id_); }
C4_ALWAYS_INLINE bool is_key_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_ref(id_); }
C4_ALWAYS_INLINE bool is_val_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_ref(id_); }
C4_ALWAYS_INLINE bool is_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_ref(id_); }
C4_ALWAYS_INLINE bool is_anchor_or_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_anchor_or_ref(id_); }
C4_ALWAYS_INLINE bool is_key_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_quoted(id_); }
C4_ALWAYS_INLINE bool is_val_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_quoted(id_); }
C4_ALWAYS_INLINE bool is_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_quoted(id_); }
C4_ALWAYS_INLINE bool parent_is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_seq(id_); }
C4_ALWAYS_INLINE bool parent_is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_map(id_); }
C4_ALWAYS_INLINE bool empty() const RYML_NOEXCEPT { _C4RR(); return tree_->empty(id_); } /**< Forward to Tree::empty(). Node must be readable. */
C4_ALWAYS_INLINE bool is_stream() const RYML_NOEXCEPT { _C4RR(); return tree_->is_stream(id_); } /**< Forward to Tree::is_stream(). Node must be readable. */
C4_ALWAYS_INLINE bool is_doc() const RYML_NOEXCEPT { _C4RR(); return tree_->is_doc(id_); } /**< Forward to Tree::is_doc(). Node must be readable. */
C4_ALWAYS_INLINE bool is_container() const RYML_NOEXCEPT { _C4RR(); return tree_->is_container(id_); } /**< Forward to Tree::is_container(). Node must be readable. */
C4_ALWAYS_INLINE bool is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->is_map(id_); } /**< Forward to Tree::is_map(). Node must be readable. */
C4_ALWAYS_INLINE bool is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->is_seq(id_); } /**< Forward to Tree::is_seq(). Node must be readable. */
C4_ALWAYS_INLINE bool has_val() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val(id_); } /**< Forward to Tree::has_val(). Node must be readable. */
C4_ALWAYS_INLINE bool has_key() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key(id_); } /**< Forward to Tree::has_key(). Node must be readable. */
C4_ALWAYS_INLINE bool is_val() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val(id_); } /**< Forward to Tree::is_val(). Node must be readable. */
C4_ALWAYS_INLINE bool is_keyval() const RYML_NOEXCEPT { _C4RR(); return tree_->is_keyval(id_); } /**< Forward to Tree::is_keyval(). Node must be readable. */
C4_ALWAYS_INLINE bool has_key_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_tag(id_); } /**< Forward to Tree::has_key_tag(). Node must be readable. */
C4_ALWAYS_INLINE bool has_val_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_tag(id_); } /**< Forward to Tree::has_val_tag(). Node must be readable. */
C4_ALWAYS_INLINE bool has_key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_anchor(id_); } /**< Forward to Tree::has_key_anchor(). Node must be readable. */
C4_ALWAYS_INLINE bool is_key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_anchor(id_); } /**< Forward to Tree::is_key_anchor(). Node must be readable. */
C4_ALWAYS_INLINE bool has_val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_anchor(id_); } /**< Forward to Tree::has_val_anchor(). Node must be readable. */
C4_ALWAYS_INLINE bool is_val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_anchor(id_); } /**< Forward to Tree::is_val_anchor(). Node must be readable. */
C4_ALWAYS_INLINE bool has_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_anchor(id_); } /**< Forward to Tree::has_anchor(). Node must be readable. */
C4_ALWAYS_INLINE bool is_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->is_anchor(id_); } /**< Forward to Tree::is_anchor(). Node must be readable. */
C4_ALWAYS_INLINE bool is_key_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_ref(id_); } /**< Forward to Tree::is_key_ref(). Node must be readable. */
C4_ALWAYS_INLINE bool is_val_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_ref(id_); } /**< Forward to Tree::is_val_ref(). Node must be readable. */
C4_ALWAYS_INLINE bool is_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_ref(id_); } /**< Forward to Tree::is_ref(). Node must be readable. */
C4_ALWAYS_INLINE bool is_anchor_or_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_anchor_or_ref(id_); } /**< Forward to Tree::is_anchor_or_ref(. Node must be readable. */
C4_ALWAYS_INLINE bool is_key_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_quoted(id_); } /**< Forward to Tree::is_key_quoted(). Node must be readable. */
C4_ALWAYS_INLINE bool is_val_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_quoted(id_); } /**< Forward to Tree::is_val_quoted(). Node must be readable. */
C4_ALWAYS_INLINE bool is_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_quoted(id_); } /**< Forward to Tree::is_quoted(). Node must be readable. */
C4_ALWAYS_INLINE bool parent_is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_seq(id_); } /**< Forward to Tree::parent_is_seq(). Node must be readable. */
C4_ALWAYS_INLINE bool parent_is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_map(id_); } /**< Forward to Tree::parent_is_map(). Node must be readable. */
/** @} */
@@ -238,17 +260,17 @@ public:
/** @name hierarchy predicates */
/** @{ */
C4_ALWAYS_INLINE bool is_root() const RYML_NOEXCEPT { _C4RR(); return tree_->is_root(id_); }
C4_ALWAYS_INLINE bool has_parent() const RYML_NOEXCEPT { _C4RR(); return tree_->has_parent(id_); }
C4_ALWAYS_INLINE bool is_root() const RYML_NOEXCEPT { _C4RR(); return tree_->is_root(id_); } /**< Forward to Tree::is_root(). Node must be readable. */
C4_ALWAYS_INLINE bool has_parent() const RYML_NOEXCEPT { _C4RR(); return tree_->has_parent(id_); } /**< Forward to Tree::has_parent() Node must be readable. */
C4_ALWAYS_INLINE bool has_child(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_child(id_, n.m_id) : false; }
C4_ALWAYS_INLINE bool has_child(size_t node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, node); }
C4_ALWAYS_INLINE bool has_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, name); }
C4_ALWAYS_INLINE bool has_children() const RYML_NOEXCEPT { _C4RR(); return tree_->has_children(id_); }
C4_ALWAYS_INLINE bool has_child(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_child(id_, n.m_id) : false; } /**< Node must be readable. */
C4_ALWAYS_INLINE bool has_child(size_t node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, node); } /**< Node must be readable. */
C4_ALWAYS_INLINE bool has_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, name); } /**< Node must be readable. */
C4_ALWAYS_INLINE bool has_children() const RYML_NOEXCEPT { _C4RR(); return tree_->has_children(id_); } /**< Node must be readable. */
C4_ALWAYS_INLINE bool has_sibling(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_sibling(id_, n.m_id) : false; }
C4_ALWAYS_INLINE bool has_sibling(size_t node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, node); }
C4_ALWAYS_INLINE bool has_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, name); }
C4_ALWAYS_INLINE bool has_sibling(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_sibling(id_, n.m_id) : false; } /**< Node must be readable. */
C4_ALWAYS_INLINE bool has_sibling(size_t node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, node); } /**< Node must be readable. */
C4_ALWAYS_INLINE bool has_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, name); } /**< Node must be readable. */
/** does not count with this */
C4_ALWAYS_INLINE bool has_other_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->has_other_siblings(id_); }
@@ -262,65 +284,66 @@ public:
/** @name hierarchy getters */
/** @{ */
/** succeeds even when the node may have invalid or seed id */
template<class U=Impl>
C4_ALWAYS_INLINE auto doc(size_t num) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { RYML_ASSERT(tree_); return {tree__, tree__->doc(num)}; }
/** succeeds even when the node may have invalid or seed id */
C4_ALWAYS_INLINE ConstImpl doc(size_t num) const RYML_NOEXCEPT { RYML_ASSERT(tree_); return {tree_, tree_->doc(num)}; }
C4_ALWAYS_INLINE auto doc(size_t i) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { RYML_ASSERT(tree_); return {tree__, tree__->doc(i)}; } /**< Forward to Tree::doc(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl doc(size_t i) const RYML_NOEXCEPT { RYML_ASSERT(tree_); return {tree_, tree_->doc(i)}; } /**< Forward to Tree::doc(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto parent() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->parent(id__)}; }
C4_ALWAYS_INLINE ConstImpl parent() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->parent(id_)}; }
C4_ALWAYS_INLINE auto parent() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->parent(id__)}; } /**< Forward to Tree::parent(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl parent() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->parent(id_)}; } /**< Forward to Tree::parent(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto first_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_child(id__)}; }
C4_ALWAYS_INLINE ConstImpl first_child() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_child(id_)}; }
C4_ALWAYS_INLINE auto first_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_child(id__)}; } /**< Forward to Tree::first_child(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl first_child() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_child(id_)}; } /**< Forward to Tree::first_child(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto last_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_child(id__)}; }
C4_ALWAYS_INLINE ConstImpl last_child () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_child (id_)}; }
C4_ALWAYS_INLINE auto last_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_child(id__)}; } /**< Forward to Tree::last_child(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl last_child () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_child (id_)}; } /**< Forward to Tree::last_child(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto child(size_t pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->child(id__, pos)}; }
C4_ALWAYS_INLINE ConstImpl child(size_t pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->child(id_, pos)}; }
C4_ALWAYS_INLINE auto child(size_t pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->child(id__, pos)}; } /**< Forward to Tree::child(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl child(size_t pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->child(id_, pos)}; } /**< Forward to Tree::child(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto find_child(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_child(id__, name)}; }
C4_ALWAYS_INLINE ConstImpl find_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_child(id_, name)}; }
C4_ALWAYS_INLINE auto find_child(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_child(id__, name)}; } /**< Forward to Tree::first_child(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl find_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_child(id_, name)}; } /**< Forward to Tree::first_child(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto prev_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->prev_sibling(id__)}; }
C4_ALWAYS_INLINE ConstImpl prev_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->prev_sibling(id_)}; }
C4_ALWAYS_INLINE auto prev_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->prev_sibling(id__)}; } /**< Forward to Tree::prev_sibling(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl prev_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->prev_sibling(id_)}; } /**< Forward to Tree::prev_sibling(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto next_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->next_sibling(id__)}; }
C4_ALWAYS_INLINE ConstImpl next_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->next_sibling(id_)}; }
C4_ALWAYS_INLINE auto next_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->next_sibling(id__)}; } /**< Forward to Tree::next_sibling(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl next_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->next_sibling(id_)}; } /**< Forward to Tree::next_sibling(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto first_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_sibling(id__)}; }
C4_ALWAYS_INLINE ConstImpl first_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_sibling(id_)}; }
C4_ALWAYS_INLINE auto first_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_sibling(id__)}; } /**< Forward to Tree::first_sibling(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl first_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_sibling(id_)}; } /**< Forward to Tree::first_sibling(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto last_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_sibling(id__)}; }
C4_ALWAYS_INLINE ConstImpl last_sibling () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_sibling(id_)}; }
C4_ALWAYS_INLINE auto last_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_sibling(id__)}; } /**< Forward to Tree::last_sibling(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl last_sibling () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_sibling(id_)}; } /**< Forward to Tree::last_sibling(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto sibling(size_t pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->sibling(id__, pos)}; }
C4_ALWAYS_INLINE ConstImpl sibling(size_t pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->sibling(id_, pos)}; }
C4_ALWAYS_INLINE auto sibling(size_t pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->sibling(id__, pos)}; } /**< Forward to Tree::sibling(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl sibling(size_t pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->sibling(id_, pos)}; } /**< Forward to Tree::sibling(). Node must be readable. */
template<class U=Impl>
C4_ALWAYS_INLINE auto find_sibling(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_sibling(id__, name)}; }
C4_ALWAYS_INLINE ConstImpl find_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_sibling(id_, name)}; }
C4_ALWAYS_INLINE auto find_sibling(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_sibling(id__, name)}; } /**< Forward to Tree::find_sibling(). Node must be readable. */
C4_ALWAYS_INLINE ConstImpl find_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_sibling(id_, name)}; } /**< Forward to Tree::find_sibling(). Node must be readable. */
/** O(#num_children) */
C4_ALWAYS_INLINE size_t child_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_CB_ASSERT(tree_->m_callbacks, n.readable()); return tree_->child_pos(id_, n.m_id); }
/** O(#num_children) */
/** O(num_children). Forward to Tree::num_children(). */
C4_ALWAYS_INLINE size_t num_children() const RYML_NOEXCEPT { _C4RR(); return tree_->num_children(id_); }
/** O(#num_siblings) */
C4_ALWAYS_INLINE size_t num_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->num_siblings(id_); }
/** O(num_siblings). Return the number of siblings except this. */
C4_ALWAYS_INLINE size_t num_other_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->num_other_siblings(id_); }
/** O(num_children). Return the position of a child within this node, using Tree::child_pos(). */
C4_ALWAYS_INLINE size_t child_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_CB_ASSERT(tree_->m_callbacks, n.readable()); return tree_->child_pos(id_, n.m_id); }
/** O(num_siblings) */
C4_ALWAYS_INLINE size_t sibling_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_CB_ASSERT(tree_->callbacks(), n.readable()); return tree_->child_pos(tree_->parent(id_), n.m_id); }
/** @} */
@@ -551,7 +574,7 @@ public:
public:
/** deserialization */
/** @name deserialization */
/** @{ */
template<class T>
@@ -746,14 +769,12 @@ public:
C4_SUPPRESS_WARNING_GCC_CLANG_POP
};
} // namespace detail
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** This object holds a pointer to an existing tree, and a node id. It
* can be used only to read from the tree.
/** Holds a pointer to an existing tree, and a node id. It can be used
* only to read from the tree.
*
* @warning The lifetime of the tree must be larger than that of this
* object. It is up to the user to ensure that this happens. */
@@ -843,11 +864,13 @@ public:
C4_ALWAYS_INLINE bool operator== (ConstNodeRef const& that) const RYML_NOEXCEPT { return that.m_tree == m_tree && m_id == that.m_id; }
C4_ALWAYS_INLINE bool operator!= (ConstNodeRef const& that) const RYML_NOEXCEPT { return ! this->operator== (that); }
/** @cond dev */
RYML_DEPRECATED("use invalid()") bool operator== (std::nullptr_t) const noexcept { return m_tree == nullptr || m_id == NONE; }
RYML_DEPRECATED("use !invalid()") bool operator!= (std::nullptr_t) const noexcept { return !(m_tree == nullptr || m_id == NONE); }
RYML_DEPRECATED("use (this->val() == s)") bool operator== (csubstr s) const RYML_NOEXCEPT { RYML_ASSERT(m_tree); _RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE); return m_tree->val(m_id) == s; }
RYML_DEPRECATED("use (this->val() != s)") bool operator!= (csubstr s) const RYML_NOEXCEPT { RYML_ASSERT(m_tree); _RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE); return m_tree->val(m_id) != s; }
/** @endcond */
/** @} */
@@ -863,10 +886,10 @@ public:
*
* Unlike its imutable ConstNodeRef peer, a NodeRef can be used to
* mutate the tree, both by writing to existing nodes and by creating
* new nodes to subsequently write to. So, semantically, a NodeRef
* new nodes to subsequently write to. Semantically, a NodeRef
* object can be in one of three states:
*
* ```
* ```text
* invalid := not pointing at anything
* readable := points at an existing tree/node
* seed := points at an existing tree, and the node
@@ -875,11 +898,11 @@ public:
*
* So both `readable` and `seed` are states where the node is also `valid`.
*
* ```c++
* Tree tree = parse("{a: b}");
* ```cpp
* Tree t = parse_in_arena("{a: b}");
* NodeRef invalid; // not pointing at anything.
* NodeRef readable = tree["a"]; // also valid, because "a" exists
* NodeRef seed = tree["none"]; // also valid, but is seed because "none" is not in the map
* NodeRef readable = t["a"]; // also valid, because "a" exists
* NodeRef seed = t["none"]; // also valid, but is seed because "none" is not in the map
* ```
*
* When the object is in seed state, using it to read from the tree is
@@ -943,6 +966,8 @@ public:
NodeRef(Tree *t, size_t id, csubstr seed_key) : m_tree(t), m_id(id), m_seed(seed_key) {}
NodeRef(std::nullptr_t) : m_tree(nullptr), m_id(NONE), m_seed() {}
inline void _clear_seed() { /*do the following manually or an assert is triggered: */ m_seed.str = nullptr; m_seed.len = NONE; }
/** @} */
public:
@@ -972,8 +997,6 @@ public:
RYML_DEPRECATED("use one of readable(), is_seed() or !invalid()") inline bool valid() const { return m_tree != nullptr && m_id != NONE; }
inline void _clear_seed() { /*do the following manually or an assert is triggered: */ m_seed.str = nullptr; m_seed.len = NONE; }
/** @} */
public:
@@ -1004,18 +1027,20 @@ public:
inline bool operator== (ConstNodeRef const& that) const { return m_tree == that.m_tree && m_id == that.m_id && !is_seed(); }
inline bool operator!= (ConstNodeRef const& that) const { return ! this->operator==(that); }
/** @cond dev */
RYML_DEPRECATED("use !readable()") bool operator== (std::nullptr_t) const { return m_tree == nullptr || m_id == NONE || is_seed(); }
RYML_DEPRECATED("use readable()") bool operator!= (std::nullptr_t) const { return !(m_tree == nullptr || m_id == NONE || is_seed()); }
RYML_DEPRECATED("use (this->val() == s)") bool operator== (csubstr s) const { _C4RV(); _RYML_CB_ASSERT(m_tree->m_callbacks, has_val()); return m_tree->val(m_id) == s; }
RYML_DEPRECATED("use (this->val() != s)") bool operator!= (csubstr s) const { _C4RV(); _RYML_CB_ASSERT(m_tree->m_callbacks, has_val()); return m_tree->val(m_id) != s; }
RYML_DEPRECATED("use `this->val() == s`") bool operator== (csubstr s) const { _C4RV(); _RYML_CB_ASSERT(m_tree->m_callbacks, has_val()); return m_tree->val(m_id) == s; }
RYML_DEPRECATED("use `this->val() != s`") bool operator!= (csubstr s) const { _C4RV(); _RYML_CB_ASSERT(m_tree->m_callbacks, has_val()); return m_tree->val(m_id) != s; }
/** @endcond */
/** @} */
public:
/** @name node property getters */
/** @{ */
/** @name node_property_getters
* @{ */
C4_ALWAYS_INLINE C4_PURE Tree * tree() noexcept { return m_tree; }
C4_ALWAYS_INLINE C4_PURE Tree const* tree() const noexcept { return m_tree; }
@@ -1026,7 +1051,7 @@ public:
public:
/** @name node modifiers */
/** @name node_modifiers */
/** @{ */
void create() { _apply_seed(); }
@@ -1075,8 +1100,6 @@ public:
* blob */
size_t set_val_serialized(fmt::const_base64_wrapper w);
public:
inline void clear()
{
if(is_seed())
@@ -1309,8 +1332,6 @@ public:
return r;
}
public:
inline NodeRef insert_sibling(ConstNodeRef const& after)
{
_C4RV();
@@ -1507,6 +1528,11 @@ inline ConstNodeRef& ConstNodeRef::operator= (NodeRef && that)
//-----------------------------------------------------------------------------
/** @addtogroup doc_serialization_helpers
*
* @{
*/
template<class T>
inline void write(NodeRef *n, T const& v)
{
@@ -1539,6 +1565,10 @@ inline read(ConstNodeRef const& n, T *v)
return from_chars_float(n.val(), v);
}
/** @} */
/** @} */
} // namespace yml
} // namespace c4

View File

@@ -426,7 +426,8 @@ void Parser::_err(csubstr fmt, Args const& C4_RESTRICT ...args) const
writer.append('\n');
_fmt_msg(dumpfn);
size_t len = writer.pos < RYML_ERRMSG_SIZE ? writer.pos : RYML_ERRMSG_SIZE;
m_tree->m_callbacks.m_error(errmsg, len, m_state->pos, m_tree->m_callbacks.m_user_data);
c4::yml::error(m_tree->m_callbacks, errmsg, len, m_state->pos);
C4_UNREACHABLE_AFTER_ERR();
}
//-----------------------------------------------------------------------------
@@ -1043,8 +1044,7 @@ bool Parser::_handle_seq_flow()
{
_c4err("internal error");
}
return true;
C4_UNREACHABLE();
}
//-----------------------------------------------------------------------------
@@ -1572,8 +1572,7 @@ bool Parser::_handle_map_flow()
{
_c4err("internal error");
}
return false;
C4_UNREACHABLE();
}
//-----------------------------------------------------------------------------
@@ -1849,8 +1848,7 @@ bool Parser::_handle_map_blck()
{
_c4err("internal error");
}
return false;
C4_UNREACHABLE();
}
@@ -1900,8 +1898,7 @@ bool Parser::_handle_top()
{
_c4err("parse error");
}
return false;
C4_UNREACHABLE();
}
@@ -1934,8 +1931,7 @@ bool Parser::_handle_key_anchors_and_refs()
else if(C4_UNLIKELY(rem.begins_with('*')))
{
_c4err("not implemented - this should have been catched elsewhere");
C4_NEVER_REACH();
return false;
C4_UNREACHABLE();
}
return false;
}
@@ -1993,8 +1989,7 @@ bool Parser::_handle_val_anchors_and_refs()
else if(C4_UNLIKELY(rem.begins_with('*')))
{
_c4err("not implemented - this should have been catched elsewhere");
C4_NEVER_REACH();
return false;
C4_UNREACHABLE();
}
return false;
}

View File

@@ -1,6 +1,8 @@
#ifndef _C4_YML_PARSE_HPP_
#define _C4_YML_PARSE_HPP_
/** @file parse.hpp Utilities to parse YAML and JSON */
#ifndef _C4_YML_TREE_HPP_
#include "c4/yml/tree.hpp"
#endif
@@ -23,6 +25,12 @@
namespace c4 {
namespace yml {
/** @addtogroup doc_parse
*
* @{
*/
/** Options to initialize a @ref Parser object. */
struct RYML_EXPORT ParserOptions
{
private:
@@ -57,6 +65,7 @@ public:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A reusable object to parse YAML/JSON and create the ryml @ref Tree. */
class RYML_EXPORT Parser
{
public:
@@ -141,7 +150,10 @@ public:
public:
/** @name parse_in_place */
/** @name parse_in_place
*
* parse a mutable buffer in situ, potentially mutating it.
*/
/** @{ */
/** Create a new tree and parse into its root.
@@ -185,8 +197,10 @@ public:
public:
/** @name parse_in_arena: copy the YAML source buffer to the
* tree's arena, then parse the copy in situ
/** @name parse_in_arena
*
* copy the YAML source buffer to the tree's arena, then parse the
* copy in situ
*
* @note overloads receiving a substr YAML buffer are intentionally
* left undefined, such that calling parse_in_arena() with a substr
@@ -201,10 +215,12 @@ public:
// READ THE NOTE ABOVE!
#define RYML_DONT_PARSE_SUBSTR_IN_ARENA "Do not pass a (mutable) substr to parse_in_arena(); if you have a substr, it should be parsed in place. Consider using parse_in_place() instead, or convert the buffer to csubstr prior to calling. This function is deliberately left undefined and will cause a linker error."
/** @cond dev */
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr csrc);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, Tree *t);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, Tree *t, size_t node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, NodeRef node);
/** @endcond */
/** Create a new tree and parse into its root.
* The immutable YAML source is first copied to the tree's arena,
@@ -253,10 +269,12 @@ public:
this->parse_in_place(filename, src, node.tree(), node.id());
}
/** @cond dev */
RYML_DEPRECATED("use parse_in_arena() instead") Tree parse(csubstr filename, csubstr csrc) { return parse_in_arena(filename, csrc); }
RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, Tree *t) { parse_in_arena(filename, csrc, t); }
RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, Tree *t, size_t node_id) { parse_in_arena(filename, csrc, t, node_id); }
RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, NodeRef node) { parse_in_arena(filename, csrc, node); }
/** @endcond */
/** @} */
@@ -565,7 +583,7 @@ private:
#ifdef RYML_DBG
template<class ...Args> void _dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const;
#endif
template<class ...Args> void _err(csubstr fmt, Args const& C4_RESTRICT ...args) const;
template<class ...Args> [[noreturn]] void _err(csubstr fmt, Args const& C4_RESTRICT ...args) const;
template<class DumpFn> void _fmt_msg(DumpFn &&dumpfn) const;
static csubstr _prfl(substr buf, flag_t v);
@@ -608,17 +626,19 @@ private:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @name parse_in_place
/** @defgroup doc_parse_in_place Parse in place
*
* @desc parse a mutable YAML source buffer.
* Parse a mutable YAML source buffer to create a ryml @ref Tree,
* potentially mutating the buffer.
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to easily parse YAML without the need
* to instantiate a separate parser. Note that some properties
* (notably node locations in the original source code) are only
* available through the parser object after it has parsed the
* code. If you need access to any of these properties, use
* Parser::parse_in_place() */
* These freestanding functions use a temporary parser object, and are
* convenience functions to easily parse YAML without the need to
* instantiate a separate parser. Note that some properties (notably
* node locations in the original source code) are only available
* through the parser object after it has parsed the code. If you need
* access to any of these properties, use Parser::parse_in_place().
*
* @see Parser */
/** @{ */
inline Tree parse_in_place( substr yaml ) { Parser np; return np.parse_in_place({} , yaml); } //!< parse in-situ a modifiable YAML source buffer.
@@ -630,6 +650,7 @@ inline void parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_i
inline void parse_in_place( substr yaml, NodeRef node ) { Parser np; np.parse_in_place({} , yaml, node); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
inline void parse_in_place(csubstr filename, substr yaml, NodeRef node ) { Parser np; np.parse_in_place(filename, yaml, node); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
/** @cond dev */
RYML_DEPRECATED("use parse_in_place() instead") inline Tree parse( substr yaml ) { Parser np; return np.parse_in_place({} , yaml); }
RYML_DEPRECATED("use parse_in_place() instead") inline Tree parse(csubstr filename, substr yaml ) { Parser np; return np.parse_in_place(filename, yaml); }
RYML_DEPRECATED("use parse_in_place() instead") inline void parse( substr yaml, Tree *t ) { Parser np; np.parse_in_place({} , yaml, t); }
@@ -638,22 +659,25 @@ RYML_DEPRECATED("use parse_in_place() instead") inline void parse(
RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place(filename, yaml, t, node_id); }
RYML_DEPRECATED("use parse_in_place() instead") inline void parse( substr yaml, NodeRef node ) { Parser np; np.parse_in_place({} , yaml, node); }
RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, NodeRef node ) { Parser np; np.parse_in_place(filename, yaml, node); }
/** @endcond */
/** @} */
//-----------------------------------------------------------------------------
/** @name parse_in_arena
* @desc parse a read-only YAML source buffer, copying it first to the tree's arena.
/** @defgroup doc_parse_in_arena Parse in arena
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to easily parse YAML without the need
* to instantiate a separate parser. Note that some properties
* (notably node locations in the original source code) are only
* available through the parser object after it has parsed the
* code. If you need access to any of these properties, use
* Parser::parse_in_arena().
* Parse a read-only YAML source buffer to create a ryml @ref Tree,
* copying the buffer first to the tree's arena. The copy of the
* buffer is then parsed in place.
*
* These freestanding functions use a temporary parser object, and are
* convenience functions to easily parse YAML without the need to
* instantiate a separate parser. Note that some properties (notably
* node locations in the original source code) are only available
* through the parser object after it has parsed the code. If you need
* access to any of these properties, use Parser::parse_in_arena().
*
* @note overloads receiving a substr YAML buffer are intentionally
* left undefined, such that calling parse_in_arena() with a substr
@@ -663,10 +687,13 @@ RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filena
* a mutable buffer in the tree's arena, convert it first to immutable
* by assigning the substr to a csubstr prior to calling parse_in_arena().
* This is not needed for parse_in_place() because csubstr is not
* implicitly convertible to substr. */
* implicitly convertible to substr.
*
* @see Parser */
/** @{ */
/* READ THE NOTE ABOVE! */
/** @cond dev */
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena( substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t );
@@ -675,6 +702,7 @@ RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t, size_t node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, NodeRef node );
/** @endcond */
inline Tree parse_in_arena( csubstr yaml ) { Parser np; return np.parse_in_arena({} , yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena.
inline Tree parse_in_arena(csubstr filename, csubstr yaml ) { Parser np; return np.parse_in_arena(filename, yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
@@ -685,6 +713,7 @@ inline void parse_in_arena(csubstr filename, csubstr yaml, Tree *t, size_t node_
inline void parse_in_arena( csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena({} , yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
inline void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena(filename, yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
/** @cond dev */
RYML_DEPRECATED("use parse_in_arena() instead") inline Tree parse( csubstr yaml ) { Parser np; return np.parse_in_arena({} , yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena.
RYML_DEPRECATED("use parse_in_arena() instead") inline Tree parse(csubstr filename, csubstr yaml ) { Parser np; return np.parse_in_arena(filename, yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse( csubstr yaml, Tree *t ) { Parser np; np.parse_in_arena({} , yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
@@ -693,7 +722,9 @@ RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse( csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena({} , yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena(filename, yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
/** @endcond */
/** @} */
/** @} */
} // namespace yml

View File

@@ -3,16 +3,6 @@
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
/** @defgroup Preprocessors Preprocessor functions
*
* These are the existing preprocessors:
*
* @code{.cpp}
* size_t preprocess_json(csubstr json, substr buf)
* size_t preprocess_rxmap(csubstr json, substr buf)
* @endcode
*/
#ifndef _C4_YML_COMMON_HPP_
#include "./common.hpp"
#endif
@@ -22,6 +12,11 @@
namespace c4 {
namespace yml {
/** @addtogroup doc_preprocessors
* @{
*/
/** @cond dev */
namespace detail {
using Preprocessor = size_t(csubstr, substr);
template<Preprocessor PP, class CharContainer>
@@ -41,13 +36,15 @@ substr preprocess_into_container(csubstr input, CharContainer *out)
return to_substr(*out).first(sz);
}
} // namespace detail
/** @endcond */
//-----------------------------------------------------------------------------
/** @name preprocess_rxmap
* Convert flow-type relaxed maps (with implicit bools) into strict YAML
* flow map.
/** @defgroup doc_preprocess_rxmap preprocess_rxmap
*
* @brief Convert flow-type relaxed maps (with implicit bools) into strict YAML
* flow map:
*
* @code{.yaml}
* {a, b, c, d: [e, f], g: {a, b}}
@@ -59,10 +56,10 @@ substr preprocess_into_container(csubstr input, CharContainer *out)
* @param rxmap A relaxed map
* @param buf output buffer
* @param out output container
*
* @{
*/
//@{
/** Write into a given output buffer. This function is safe to call with
* empty or small buffers; it won't write beyond the end of the buffer.
*
@@ -91,7 +88,8 @@ CharContainer preprocess_rxmap(csubstr rxmap)
return out;
}
//@}
/** @} */ // preprocess_rxmap
/** @} */ // group
} // namespace yml
} // namespace c4

View File

@@ -1436,7 +1436,7 @@ struct ReferenceResolver
snprintf(errmsg, RYML_ERRMSG_SIZE, "anchor does not exist: '%.*s'",
static_cast<int>(refname.size()), refname.data());
c4::yml::error(errmsg);
return NONE;
C4_UNREACHABLE_AFTER_ERR();
}
void resolve()

View File

@@ -1,6 +1,7 @@
#ifndef _C4_YML_TREE_HPP_
#define _C4_YML_TREE_HPP_
/** @file tree.hpp */
#include "c4/error.hpp"
#include "c4/types.hpp"
@@ -85,13 +86,19 @@ bool from_chars_float(csubstr buf, T *C4_RESTRICT val)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @addtogroup doc_tag_utils
*
* @{
*/
/** the integral type necessary to cover all the bits marking node tags */
using tag_bits = uint16_t;
/** a bit mask for marking tags for types */
typedef enum : tag_bits {
// container types
TAG_NONE = 0,
TAG_NONE = 0, /**< no tag is set */
TAG_MAP = 1, /**< !!map Unordered set of key: value pairs without duplicates. @see https://yaml.org/type/map.html */
TAG_OMAP = 2, /**< !!omap Ordered sequence of key: value pairs without duplicates. @see https://yaml.org/type/omap.html */
TAG_PAIRS = 3, /**< !!pairs Ordered sequence of key: value pairs allowing duplicates. @see https://yaml.org/type/pairs.html */
@@ -131,6 +138,7 @@ struct TagDirective
#define RYML_MAX_TAG_DIRECTIVES 4
#endif
/** @} */
//-----------------------------------------------------------------------------
@@ -138,11 +146,17 @@ struct TagDirective
//-----------------------------------------------------------------------------
/** @addtogroup doc_node_type
*
* @{
*/
/** the integral type necessary to cover all the bits marking node types */
using type_bits = uint64_t;
/** a bit mask for marking node types */
/** a bit mask for marking node types. See NodeType */
typedef enum : type_bits {
// a convenience define, undefined below
#define c4bit(v) (type_bits(1) << v)
@@ -171,9 +185,9 @@ typedef enum : type_bits {
_KEYMASK = KEY | KEYQUO | KEYANCH | KEYREF | KEYTAG,
_VALMASK = VAL | VALQUO | VALANCH | VALREF | VALTAG,
// these flags are from a work in progress and should be used with care
_WIP_STYLE_FLOW_SL = c4bit(14), ///< mark container with single-line flow format (seqs as '[val1,val2], maps as '{key: val, key2: val2}')
_WIP_STYLE_FLOW_ML = c4bit(15), ///< mark container with multi-line flow format (seqs as '[val1,\nval2], maps as '{key: val,\nkey2: val2}')
_WIP_STYLE_BLOCK = c4bit(16), ///< mark container with block format (seqs as '- val\n', maps as 'key: val')
_WIP_STYLE_FLOW_SL = c4bit(14), ///< mark container with single-line flow format (seqs as `[val1,val2]`, maps as `{key: val, key2: val2}`)
_WIP_STYLE_FLOW_ML = c4bit(15), ///< mark container with multi-line flow format (seqs as `[val1,\nval2]`, maps as `{key: val,\nkey2: val2}`)
_WIP_STYLE_BLOCK = c4bit(16), ///< mark container with block format (seqs as `- val\n`, maps as `key: val`)
_WIP_KEY_LITERAL = c4bit(17), ///< mark key scalar as multiline, block literal |
_WIP_VAL_LITERAL = c4bit(18), ///< mark val scalar as multiline, block literal |
_WIP_KEY_FOLDED = c4bit(19), ///< mark key scalar as multiline, block folded >
@@ -299,10 +313,19 @@ public:
};
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @addtogroup doc_tree
*
* @{
*/
/** a node scalar is a csubstr, which may be tagged and anchored. */
struct NodeScalar
{
@@ -495,38 +518,36 @@ public:
size_t id(NodeData const* n) const
{
if( ! n)
{
return NONE;
}
_RYML_CB_ASSERT(m_callbacks, n >= m_buf && n < m_buf + m_cap);
return static_cast<size_t>(n - m_buf);
}
//! get a pointer to a node's NodeData.
//! i can be NONE, in which case a nullptr is returned
inline NodeData *get(size_t i)
inline NodeData *get(size_t node)
{
if(i == NONE)
if(node == NONE)
return nullptr;
_RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
return m_buf + i;
_RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap);
return m_buf + node;
}
//! get a pointer to a node's NodeData.
//! i can be NONE, in which case a nullptr is returned.
inline NodeData const *get(size_t i) const
inline NodeData const *get(size_t node) const
{
if(i == NONE)
if(node == NONE)
return nullptr;
_RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
return m_buf + i;
_RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap);
return m_buf + node;
}
//! An if-less form of get() that demands a valid node index.
//! This function is implementation only; use at your own risk.
inline NodeData * _p(size_t i) { _RYML_CB_ASSERT(m_callbacks, i != NONE && i >= 0 && i < m_cap); return m_buf + i; }
inline NodeData * _p(size_t node) { _RYML_CB_ASSERT(m_callbacks, node != NONE && node >= 0 && node < m_cap); return m_buf + node; }
//! An if-less form of get() that demands a valid node index.
//! This function is implementation only; use at your own risk.
inline NodeData const * _p(size_t i) const { _RYML_CB_ASSERT(m_callbacks, i != NONE && i >= 0 && i < m_cap); return m_buf + i; }
inline NodeData const * _p(size_t node) const { _RYML_CB_ASSERT(m_callbacks, node != NONE && node >= 0 && node < m_cap); return m_buf + node; }
//! Get the id of the root node
size_t root_id() { if(m_cap == 0) { reserve(16); } _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0); return 0; }
@@ -534,11 +555,11 @@ public:
size_t root_id() const { _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0); return 0; }
//! Get a NodeRef of a node by id
NodeRef ref(size_t id);
NodeRef ref(size_t node);
//! Get a NodeRef of a node by id
ConstNodeRef ref(size_t id) const;
ConstNodeRef ref(size_t node) const;
//! Get a NodeRef of a node by id
ConstNodeRef cref(size_t id) const;
ConstNodeRef cref(size_t node) const;
//! Get the root as a NodeRef
NodeRef rootref();
@@ -548,10 +569,10 @@ public:
ConstNodeRef crootref() const;
//! get the i-th document of the stream
//! @note @i is NOT the node id, but the doc position within the stream
//! @note @p i is NOT the node id, but the doc position within the stream
NodeRef docref(size_t i);
//! get the i-th document of the stream
//! @note @i is NOT the node id, but the doc position within the stream
//! @note @p i is NOT the node id, but the doc position within the stream
ConstNodeRef docref(size_t i) const;
//! find a root child by name, return it as a NodeRef
@@ -562,10 +583,10 @@ public:
ConstNodeRef operator[] (csubstr key) const;
//! find a root child by index: return the root node's @p i-th child as a NodeRef
//! @note @i is NOT the node id, but the child's position
//! @note @p i is NOT the node id, but the child's position
NodeRef operator[] (size_t i);
//! find a root child by index: return the root node's @p i-th child as a NodeRef
//! @note @i is NOT the node id, but the child's position
//! @note @p i is NOT the node id, but the child's position
ConstNodeRef operator[] (size_t i) const;
/** @} */
@@ -1260,6 +1281,8 @@ private:
public:
/** @cond dev*/
#if ! RYML_USE_ASSERT
C4_ALWAYS_INLINE void _check_next_flags(size_t, type_bits) {}
#else
@@ -1449,6 +1472,8 @@ public:
_rem_flags(node, VAL);
}
/** @endcond */
private:
void _clear_range(size_t first, size_t num);
@@ -1483,6 +1508,8 @@ public:
};
/** @} */
} // namespace yml
} // namespace c4

View File

@@ -13,6 +13,15 @@
namespace c4 {
namespace yml {
/** @addtogroup doc_emit
* @{
*/
/** @defgroup doc_writers Writer objects to use with an Emitter
* @see Emitter
* @{
*/
/** Repeat-Character: a character to be written a number of times. */
struct RepC
@@ -222,6 +231,10 @@ struct WriterBuf
}
};
/** @ } */
/** @ } */
} // namespace yml
} // namespace c4

View File

@@ -18,10 +18,11 @@ Location stored_location;
void * stored_mem;
size_t stored_length;
void test_error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
C4_NORETURN void test_error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
{
stored_msg = std::string(msg, length);
stored_location = loc;
throw std::runtime_error(stored_msg);
}
void* test_allocate_impl(size_t length, void * /*hint*/, void * /*user_data*/)
@@ -286,14 +287,24 @@ TEST(error, basic)
set_callbacks(cb);
// message
EXPECT_EQ(get_callbacks().m_error, &test_error_impl);
c4::yml::error("some message 123"); // calls test_error_impl, which sets stored_msg and stored_location
try {
c4::yml::error("some message 123"); // calls test_error_impl, which sets stored_msg and stored_location
}
catch (std::exception const&) {
;
}
EXPECT_EQ(stored_msg, "some message 123");
EXPECT_EQ(stored_location.name, "");
EXPECT_EQ(stored_location.offset, 0u);
EXPECT_EQ(stored_location.line, 0u);
EXPECT_EQ(stored_location.col, 0u);
// location
c4::yml::error("some message 456", Location("file.yml", 433u, 123u, 4u));
try {
c4::yml::error("some message 456", Location("file.yml", 433u, 123u, 4u));
}
catch (std::exception const&) {
;
}
EXPECT_EQ(stored_msg, "some message 456");
EXPECT_EQ(stored_location.name, "file.yml");
EXPECT_EQ(stored_location.offset, 433u);
@@ -308,7 +319,14 @@ TEST(RYML_CHECK, basic)
EXPECT_NE(get_callbacks().m_error, &test_error_impl);
Callbacks cb(nullptr, nullptr, nullptr, &test_error_impl);
set_callbacks(cb);
size_t the_line = __LINE__; RYML_CHECK(false); // keep both statements in the same line
ASSERT_EQ(get_callbacks(), cb);
size_t the_line;
try {
the_line = __LINE__; RYML_CHECK(false); // keep both statements in the same line
}
catch (std::exception const&) {
;
}
EXPECT_EQ(stored_msg, "check failed: false");
EXPECT_EQ(stored_location.name, __FILE__);
EXPECT_EQ(stored_location.offset, 0u);
@@ -326,7 +344,13 @@ TEST(RYML_ASSERT, basic)
set_callbacks(cb);
stored_msg = "";
stored_location = {};
size_t the_line = __LINE__; RYML_ASSERT(false); // keep both statements in the same line
size_t the_line;
try {
the_line = __LINE__; RYML_ASSERT(false); // keep both statements in the same line
}
catch (std::exception const&) {
;
}
#if RYML_USE_ASSERT
EXPECT_EQ(stored_msg, "check failed: false");
EXPECT_EQ(stored_location.name, __FILE__);

View File

@@ -192,9 +192,10 @@ ExpectError::ExpectError(Tree *tree, Location loc)
, m_tree_prev(tree ? tree->callbacks() : Callbacks{})
, expected_location(loc)
{
auto err = [](const char* msg, size_t len, Location errloc, void *this_) {
auto err = [](const char* msg, size_t len, Location errloc, void *this_) {
((ExpectError*)this_)->m_got_an_error = true;
throw ExpectedError(msg, len, errloc);
C4_UNREACHABLE_AFTER_ERR();
};
#ifdef RYML_NO_DEFAULT_CALLBACKS
c4::yml::Callbacks tcb((void*)this, nullptr, nullptr, err);
@@ -687,7 +688,7 @@ void test_invariants(ConstNodeRef const& n)
{
EXPECT_EQ(n.parent().num_children() > 1, n.has_other_siblings()) _MORE_INFO;
EXPECT_TRUE(n.parent().has_child(n)) _MORE_INFO;
EXPECT_EQ(n.parent().num_children(), n.num_siblings()) _MORE_INFO;
EXPECT_EQ(n.parent().num_children(), 1 + n.num_other_siblings()) _MORE_INFO;
// doc parent must be a seq and a stream
if(n.is_doc())
{

View File

@@ -27,11 +27,13 @@ int main(int argc, const char *argv[])
return 1;
}
Callbacks callbacks = {};
callbacks.m_error = [](const char *msg, size_t msg_len, Location location, void *)
pfn_error error = [](const char *msg, size_t msg_len, Location location, void *)
{
report_error(msg, msg_len, location, stderr);
throw std::runtime_error({msg, msg_len});
C4_UNREACHABLE_AFTER_ERR();
};
callbacks.m_error = error;
try {
Tree tree(callbacks);
csubstr filename = to_csubstr(argv[1]);