aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/ryml/src
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/ryml/src')
-rw-r--r--thirdparty/ryml/src/c4/yml/common.cpp117
-rw-r--r--thirdparty/ryml/src/c4/yml/common.hpp278
-rw-r--r--thirdparty/ryml/src/c4/yml/detail/checks.hpp200
-rw-r--r--thirdparty/ryml/src/c4/yml/detail/parser_dbg.hpp137
-rw-r--r--thirdparty/ryml/src/c4/yml/detail/print.hpp128
-rw-r--r--thirdparty/ryml/src/c4/yml/detail/stack.hpp274
-rw-r--r--thirdparty/ryml/src/c4/yml/emit.def.hpp960
-rw-r--r--thirdparty/ryml/src/c4/yml/emit.hpp490
-rw-r--r--thirdparty/ryml/src/c4/yml/export.hpp18
-rw-r--r--thirdparty/ryml/src/c4/yml/node.cpp30
-rw-r--r--thirdparty/ryml/src/c4/yml/node.hpp1276
-rw-r--r--thirdparty/ryml/src/c4/yml/parse.cpp5724
-rw-r--r--thirdparty/ryml/src/c4/yml/parse.hpp706
-rw-r--r--thirdparty/ryml/src/c4/yml/preprocess.cpp110
-rw-r--r--thirdparty/ryml/src/c4/yml/preprocess.hpp99
-rw-r--r--thirdparty/ryml/src/c4/yml/std/map.hpp45
-rw-r--r--thirdparty/ryml/src/c4/yml/std/std.hpp8
-rw-r--r--thirdparty/ryml/src/c4/yml/std/string.hpp9
-rw-r--r--thirdparty/ryml/src/c4/yml/std/vector.hpp53
-rw-r--r--thirdparty/ryml/src/c4/yml/tree.cpp2183
-rw-r--r--thirdparty/ryml/src/c4/yml/tree.hpp1495
-rw-r--r--thirdparty/ryml/src/c4/yml/writer.hpp229
-rw-r--r--thirdparty/ryml/src/c4/yml/yml.hpp10
-rw-r--r--thirdparty/ryml/src/ryml-gdbtypes.py391
-rw-r--r--thirdparty/ryml/src/ryml.hpp11
-rw-r--r--thirdparty/ryml/src/ryml.natvis194
-rw-r--r--thirdparty/ryml/src/ryml_std.hpp6
27 files changed, 0 insertions, 15181 deletions
diff --git a/thirdparty/ryml/src/c4/yml/common.cpp b/thirdparty/ryml/src/c4/yml/common.cpp
deleted file mode 100644
index 75b873549..000000000
--- a/thirdparty/ryml/src/c4/yml/common.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-#include "c4/yml/common.hpp"
-
-#ifndef RYML_NO_DEFAULT_CALLBACKS
-# include <stdlib.h>
-# include <stdio.h>
-#endif // RYML_NO_DEFAULT_CALLBACKS
-
-namespace c4 {
-namespace yml {
-
-namespace {
-Callbacks s_default_callbacks;
-} // anon namespace
-
-#ifndef RYML_NO_DEFAULT_CALLBACKS
-void report_error_impl(const char* msg, size_t length, Location loc, FILE *f)
-{
- if(!f)
- f = stderr;
- if(loc)
- {
- if(!loc.name.empty())
- {
- fwrite(loc.name.str, 1, loc.name.len, f);
- fputc(':', f);
- }
- fprintf(f, "%zu:", loc.line);
- if(loc.col)
- fprintf(f, "%zu:", loc.col);
- if(loc.offset)
- fprintf(f, " (%zuB):", loc.offset);
- }
- fprintf(f, "%.*s\n", (int)length, msg);
- fflush(f);
-}
-
-void error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
-{
- report_error_impl(msg, length, loc, nullptr);
- ::abort();
-}
-
-void* allocate_impl(size_t length, void * /*hint*/, void * /*user_data*/)
-{
- void *mem = ::malloc(length);
- if(mem == nullptr)
- {
- const char msg[] = "could not allocate memory";
- error_impl(msg, sizeof(msg)-1, {}, nullptr);
- }
- return mem;
-}
-
-void free_impl(void *mem, size_t /*length*/, void * /*user_data*/)
-{
- ::free(mem);
-}
-#endif // RYML_NO_DEFAULT_CALLBACKS
-
-
-
-Callbacks::Callbacks()
- :
- m_user_data(nullptr),
- #ifndef RYML_NO_DEFAULT_CALLBACKS
- m_allocate(allocate_impl),
- m_free(free_impl),
- m_error(error_impl)
- #else
- m_allocate(nullptr),
- m_free(nullptr),
- m_error(nullptr)
- #endif
-{
-}
-
-Callbacks::Callbacks(void *user_data, pfn_allocate alloc_, pfn_free free_, pfn_error error_)
- :
- m_user_data(user_data),
- #ifndef RYML_NO_DEFAULT_CALLBACKS
- m_allocate(alloc_ ? alloc_ : allocate_impl),
- m_free(free_ ? free_ : free_impl),
- m_error(error_ ? error_ : error_impl)
- #else
- m_allocate(alloc_),
- m_free(free_),
- m_error(error_)
- #endif
-{
- C4_CHECK(m_allocate);
- C4_CHECK(m_free);
- C4_CHECK(m_error);
-}
-
-
-void set_callbacks(Callbacks const& c)
-{
- s_default_callbacks = c;
-}
-
-Callbacks const& get_callbacks()
-{
- return s_default_callbacks;
-}
-
-void reset_callbacks()
-{
- set_callbacks(Callbacks());
-}
-
-void error(const char *msg, size_t msg_len, Location loc)
-{
- s_default_callbacks.m_error(msg, msg_len, loc, s_default_callbacks.m_user_data);
-}
-
-} // namespace yml
-} // namespace c4
diff --git a/thirdparty/ryml/src/c4/yml/common.hpp b/thirdparty/ryml/src/c4/yml/common.hpp
deleted file mode 100644
index 21aef6ba2..000000000
--- a/thirdparty/ryml/src/c4/yml/common.hpp
+++ /dev/null
@@ -1,278 +0,0 @@
-#ifndef _C4_YML_COMMON_HPP_
-#define _C4_YML_COMMON_HPP_
-
-#include <cstddef>
-#include <c4/substr.hpp>
-#include <c4/yml/export.hpp>
-
-
-#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)
-#else
-# define RYML_ASSERT(cond)
-# define RYML_ASSERT_MSG(cond, msg)
-#endif
-
-
-#if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK)
-# define RYML_DEBUG_BREAK()
-#else
-# define RYML_DEBUG_BREAK() \
- { \
- if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
- { \
- C4_DEBUG_BREAK(); \
- } \
- }
-#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
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-namespace c4 {
-namespace yml {
-
-enum : size_t {
- /** a null position */
- npos = size_t(-1),
- /** an index to none */
- NONE = size_t(-1)
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//! holds a position into a source buffer
-struct RYML_EXPORT LineCol
-{
- //! number of bytes from the beginning of the source buffer
- size_t offset;
- //! line
- size_t line;
- //! column
- size_t col;
-
- LineCol() : offset(), line(), col() {}
- //! construct from line and column
- LineCol(size_t l, size_t c) : offset(0), line(l), col(c) {}
- //! construct from offset, line and column
- LineCol(size_t o, size_t l, size_t c) : offset(o), line(l), col(c) {}
-};
-
-
-//! a source file position
-struct RYML_EXPORT Location : public LineCol
-{
- csubstr name;
-
- operator bool () const { return !name.empty() || line != 0 || offset != 0; }
-
- Location() : LineCol(), name() {}
- Location( size_t l, size_t c) : LineCol{ l, c}, name( ) {}
- Location( csubstr n, size_t l, size_t c) : LineCol{ l, c}, name(n) {}
- Location( csubstr n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(n) {}
- Location(const char *n, size_t l, size_t c) : LineCol{ l, c}, name(to_csubstr(n)) {}
- Location(const char *n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(to_csubstr(n)) {}
-};
-
-
-//-----------------------------------------------------------------------------
-
-/** the type of the function used to report errors. This function must
- * interrupt execution, either by raising an exception or calling
- * std::abort().
- *
- * @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 */
-using pfn_allocate = void* (*)(size_t len, void* hint, void *user_data);
-/** the type of the function used to free memory */
-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. */
-struct RYML_EXPORT Callbacks
-{
- void * m_user_data;
- pfn_allocate m_allocate;
- pfn_free m_free;
- pfn_error m_error;
-
- Callbacks();
- 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
- {
- return (m_user_data == that.m_user_data &&
- m_allocate == that.m_allocate &&
- m_free == that.m_free &&
- m_error == that.m_error);
- }
-};
-
-/** 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
-#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); \
-} while(0)
-#define _RYML_CB_CHECK(cb, cond) \
- do \
- { \
- if(!(cond)) \
- { \
- 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); \
- } \
- } while(0)
-#ifdef RYML_USE_ASSERT
-#define _RYML_CB_ASSERT(cb, cond) _RYML_CB_CHECK((cb), (cond))
-#else
-#define _RYML_CB_ASSERT(cb, cond) do {} while(0)
-#endif
-#define _RYML_CB_ALLOC_HINT(cb, T, num, hint) (T*) (cb).m_allocate((num) * sizeof(T), (hint), (cb).m_user_data)
-#define _RYML_CB_ALLOC(cb, T, num) _RYML_CB_ALLOC_HINT((cb), (T), (num), nullptr)
-#define _RYML_CB_FREE(cb, buf, T, num) \
- do { \
- (cb).m_free((buf), (num) * sizeof(T), (cb).m_user_data); \
- (buf) = nullptr; \
- } while(0)
-
-
-
-namespace detail {
-template<int8_t signedval, uint8_t unsignedval>
-struct _charconstant_t
- : public std::conditional<std::is_signed<char>::value,
- std::integral_constant<int8_t, signedval>,
- std::integral_constant<uint8_t, unsignedval>>::type
-{};
-#define _RYML_CHCONST(signedval, unsignedval) ::c4::yml::detail::_charconstant_t<INT8_C(signedval), UINT8_C(unsignedval)>::value
-} // namespace detail
-
-
-namespace detail {
-struct _SubstrWriter
-{
- substr buf;
- size_t pos;
- _SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) {}
- void append(csubstr s)
- {
- C4_ASSERT(!s.overlaps(buf));
- if(pos + s.len <= buf.len)
- memcpy(buf.str + pos, s.str, s.len);
- pos += s.len;
- }
- void append(char c)
- {
- if(pos < buf.len)
- buf.str[pos] = c;
- ++pos;
- }
- void append_n(char c, size_t numtimes)
- {
- if(pos + numtimes < buf.len)
- memset(buf.str + pos, c, numtimes);
- pos += numtimes;
- }
- size_t slack() const { return pos <= buf.len ? buf.len - pos : 0; }
- size_t excess() const { return pos > buf.len ? pos - buf.len : 0; }
- //! get the part written so far
- csubstr curr() const { return pos <= buf.len ? buf.first(pos) : buf; }
- //! get the part that is still free to write to (the remainder)
- substr rem() { return pos < buf.len ? buf.sub(pos) : buf.last(0); }
-
- size_t advance(size_t more) { pos += more; return pos; }
-};
-} // namespace detail
-
-/// @endcond
-
-} // namespace yml
-} // namespace c4
-
-#endif /* _C4_YML_COMMON_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/detail/checks.hpp b/thirdparty/ryml/src/c4/yml/detail/checks.hpp
deleted file mode 100644
index 39b49e856..000000000
--- a/thirdparty/ryml/src/c4/yml/detail/checks.hpp
+++ /dev/null
@@ -1,200 +0,0 @@
-#ifndef C4_YML_DETAIL_CHECKS_HPP_
-#define C4_YML_DETAIL_CHECKS_HPP_
-
-#include "c4/yml/tree.hpp"
-
-#ifdef __clang__
-# pragma clang diagnostic push
-#elif defined(__GNUC__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wtype-limits" // error: comparison of unsigned expression >= 0 is always true
-#elif defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4296/*expression is always 'boolean_value'*/)
-#endif
-
-namespace c4 {
-namespace yml {
-
-
-void check_invariants(Tree const& t, size_t node=NONE);
-void check_free_list(Tree const& t);
-void check_arena(Tree const& t);
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-inline void check_invariants(Tree const& t, size_t node)
-{
- if(node == NONE)
- {
- if(t.size() == 0) return;
- node = t.root_id();
- }
-
- auto const& n = *t._p(node);
-#ifdef RYML_DBG
- if(n.m_first_child != NONE || n.m_last_child != NONE)
- {
- printf("check(%zu): fc=%zu lc=%zu\n", node, n.m_first_child, n.m_last_child);
- }
- else
- {
- printf("check(%zu)\n", node);
- }
-#endif
-
- C4_CHECK(n.m_parent != node);
- if(n.m_parent == NONE)
- {
- C4_CHECK(t.is_root(node));
- }
- else //if(n.m_parent != NONE)
- {
- C4_CHECK(t.has_child(n.m_parent, node));
-
- auto const& p = *t._p(n.m_parent);
- if(n.m_prev_sibling == NONE)
- {
- C4_CHECK(p.m_first_child == node);
- C4_CHECK(t.first_sibling(node) == node);
- }
- else
- {
- C4_CHECK(p.m_first_child != node);
- C4_CHECK(t.first_sibling(node) != node);
- }
-
- if(n.m_next_sibling == NONE)
- {
- C4_CHECK(p.m_last_child == node);
- C4_CHECK(t.last_sibling(node) == node);
- }
- else
- {
- C4_CHECK(p.m_last_child != node);
- C4_CHECK(t.last_sibling(node) != node);
- }
- }
-
- C4_CHECK(n.m_first_child != node);
- C4_CHECK(n.m_last_child != node);
- if(n.m_first_child != NONE || n.m_last_child != NONE)
- {
- C4_CHECK(n.m_first_child != NONE);
- C4_CHECK(n.m_last_child != NONE);
- }
-
- C4_CHECK(n.m_prev_sibling != node);
- C4_CHECK(n.m_next_sibling != node);
- if(n.m_prev_sibling != NONE)
- {
- C4_CHECK(t._p(n.m_prev_sibling)->m_next_sibling == node);
- C4_CHECK(t._p(n.m_prev_sibling)->m_prev_sibling != node);
- }
- if(n.m_next_sibling != NONE)
- {
- C4_CHECK(t._p(n.m_next_sibling)->m_prev_sibling == node);
- C4_CHECK(t._p(n.m_next_sibling)->m_next_sibling != node);
- }
-
- size_t count = 0;
- for(size_t i = n.m_first_child; i != NONE; i = t.next_sibling(i))
- {
-#ifdef RYML_DBG
- printf("check(%zu): descend to child[%zu]=%zu\n", node, count, i);
-#endif
- auto const& ch = *t._p(i);
- C4_CHECK(ch.m_parent == node);
- C4_CHECK(ch.m_next_sibling != i);
- ++count;
- }
- C4_CHECK(count == t.num_children(node));
-
- if(n.m_prev_sibling == NONE && n.m_next_sibling == NONE)
- {
- if(n.m_parent != NONE)
- {
- C4_CHECK(t.num_children(n.m_parent) == 1);
- C4_CHECK(t.num_siblings(node) == 1);
- }
- }
-
- if(node == t.root_id())
- {
- C4_CHECK(t.size() == t.m_size);
- C4_CHECK(t.capacity() == t.m_cap);
- C4_CHECK(t.m_cap == t.m_size + t.slack());
- check_free_list(t);
- check_arena(t);
- }
-
- for(size_t i = t.first_child(node); i != NONE; i = t.next_sibling(i))
- {
- check_invariants(t, i);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-inline void check_free_list(Tree const& t)
-{
- if(t.m_free_head == NONE)
- {
- C4_CHECK(t.m_free_tail == t.m_free_head);
- return;
- }
-
- C4_CHECK(t.m_free_head >= 0 && t.m_free_head < t.m_cap);
- C4_CHECK(t.m_free_tail >= 0 && t.m_free_tail < t.m_cap);
-
- auto const& head = *t._p(t.m_free_head);
- //auto const& tail = *t._p(t.m_free_tail);
-
- //C4_CHECK(head.m_prev_sibling == NONE);
- //C4_CHECK(tail.m_next_sibling == NONE);
-
- size_t count = 0;
- for(size_t i = t.m_free_head, prev = NONE; i != NONE; i = t._p(i)->m_next_sibling)
- {
- auto const& elm = *t._p(i);
- if(&elm != &head)
- {
- C4_CHECK(elm.m_prev_sibling == prev);
- }
- prev = i;
- ++count;
- }
- C4_CHECK(count == t.slack());
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-inline void check_arena(Tree const& t)
-{
- C4_CHECK(t.m_arena.len == 0 || (t.m_arena_pos >= 0 && t.m_arena_pos <= t.m_arena.len));
- C4_CHECK(t.arena_size() == t.m_arena_pos);
- C4_CHECK(t.arena_slack() + t.m_arena_pos == t.m_arena.len);
-}
-
-
-} /* namespace yml */
-} /* namespace c4 */
-
-#ifdef __clang__
-# pragma clang diagnostic pop
-#elif defined(__GNUC__)
-# pragma GCC diagnostic pop
-#elif defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-#endif /* C4_YML_DETAIL_CHECKS_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/detail/parser_dbg.hpp b/thirdparty/ryml/src/c4/yml/detail/parser_dbg.hpp
deleted file mode 100644
index 457f1700d..000000000
--- a/thirdparty/ryml/src/c4/yml/detail/parser_dbg.hpp
+++ /dev/null
@@ -1,137 +0,0 @@
-#ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
-#define _C4_YML_DETAIL_PARSER_DBG_HPP_
-
-#ifndef _C4_YML_COMMON_HPP_
-#include "../common.hpp"
-#endif
-#include <cstdio>
-
-//-----------------------------------------------------------------------------
-// some debugging scaffolds
-
-#if defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4068/*unknown pragma*/)
-#endif
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunknown-pragmas"
-//#pragma GCC diagnostic ignored "-Wpragma-system-header-outside-header"
-#pragma GCC system_header
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Werror"
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-
-// some debugging scaffolds
-#ifdef RYML_DBG
-#include <c4/dump.hpp>
-namespace c4 {
-inline void _dbg_dumper(csubstr s) { fwrite(s.str, 1, s.len, stdout); };
-template<class ...Args>
-void _dbg_printf(c4::csubstr fmt, Args&& ...args)
-{
- static char writebuf[256];
- auto results = c4::format_dump_resume<&_dbg_dumper>(writebuf, fmt, std::forward<Args>(args)...);
- // resume writing if the results failed to fit the buffer
- if(C4_UNLIKELY(results.bufsize > sizeof(writebuf))) // bufsize will be that of the largest element serialized. Eg int(1), will require 1 byte.
- {
- results = format_dump_resume<&_dbg_dumper>(results, writebuf, fmt, std::forward<Args>(args)...);
- if(C4_UNLIKELY(results.bufsize > sizeof(writebuf)))
- {
- results = format_dump_resume<&_dbg_dumper>(results, writebuf, fmt, std::forward<Args>(args)...);
- }
- }
-}
-} // namespace c4
-
-# define _c4dbgt(fmt, ...) this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, ## __VA_ARGS__)
-# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__)
-# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
-# define _c4dbgq(msg) _dbg_printf(msg "\n")
-# define _c4err(fmt, ...) \
- do { if(c4::is_debugger_attached()) { C4_DEBUG_BREAK(); } \
- this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__, ## __VA_ARGS__); } while(0)
-#else
-# define _c4dbgt(fmt, ...)
-# define _c4dbgpf(fmt, ...)
-# define _c4dbgp(msg)
-# define _c4dbgq(msg)
-# define _c4err(fmt, ...) \
- do { if(c4::is_debugger_attached()) { C4_DEBUG_BREAK(); } \
- this->_err("ERROR: " fmt, ## __VA_ARGS__); } while(0)
-#endif
-
-#define _c4prsp(sp) sp
-#define _c4presc(s) __c4presc(s.str, s.len)
-inline c4::csubstr _c4prc(const char &C4_RESTRICT c)
-{
- switch(c)
- {
- case '\n': return c4::csubstr("\\n");
- case '\t': return c4::csubstr("\\t");
- case '\0': return c4::csubstr("\\0");
- case '\r': return c4::csubstr("\\r");
- case '\f': return c4::csubstr("\\f");
- case '\b': return c4::csubstr("\\b");
- case '\v': return c4::csubstr("\\v");
- case '\a': return c4::csubstr("\\a");
- default: return c4::csubstr(&c, 1);
- }
-}
-inline void __c4presc(const char *s, size_t len)
-{
- size_t prev = 0;
- for(size_t i = 0; i < len; ++i)
- {
- switch(s[i])
- {
- case '\n' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('n'); putchar('\n'); prev = i+1; break;
- case '\t' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('t'); prev = i+1; break;
- case '\0' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('0'); prev = i+1; break;
- case '\r' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('r'); prev = i+1; break;
- case '\f' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('f'); prev = i+1; break;
- case '\b' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('b'); prev = i+1; break;
- case '\v' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('v'); prev = i+1; break;
- case '\a' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('a'); prev = i+1; break;
- case '\x1b': fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('e'); prev = i+1; break;
- case -0x3e/*0xc2u*/:
- if(i+1 < len)
- {
- if(s[i+1] == -0x60/*0xa0u*/)
- {
- fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('_'); prev = i+2; ++i;
- }
- else if(s[i+1] == -0x7b/*0x85u*/)
- {
- fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('N'); prev = i+2; ++i;
- }
- break;
- }
- case -0x1e/*0xe2u*/:
- if(i+2 < len && s[i+1] == -0x80/*0x80u*/)
- {
- if(s[i+2] == -0x58/*0xa8u*/)
- {
- fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('L'); prev = i+3; i += 2;
- }
- else if(s[i+2] == -0x57/*0xa9u*/)
- {
- fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('P'); prev = i+3; i += 2;
- }
- break;
- }
- }
- }
- fwrite(s + prev, 1, len - prev, stdout);
-}
-
-#pragma clang diagnostic pop
-#pragma GCC diagnostic pop
-
-#if defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-
-#endif /* _C4_YML_DETAIL_PARSER_DBG_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/detail/print.hpp b/thirdparty/ryml/src/c4/yml/detail/print.hpp
deleted file mode 100644
index f88dc251d..000000000
--- a/thirdparty/ryml/src/c4/yml/detail/print.hpp
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef C4_YML_DETAIL_PRINT_HPP_
-#define C4_YML_DETAIL_PRINT_HPP_
-
-#include "c4/yml/tree.hpp"
-#include "c4/yml/node.hpp"
-
-
-namespace c4 {
-namespace yml {
-
-
-inline size_t print_node(Tree const& p, size_t node, int level, size_t count, bool print_children)
-{
- printf("[%zd]%*s[%zd] %p", count, (2*level), "", node, (void*)p.get(node));
- if(p.is_root(node))
- {
- printf(" [ROOT]");
- }
- printf(" %s:", p.type_str(node));
- if(p.has_key(node))
- {
- if(p.has_key_anchor(node))
- {
- csubstr ka = p.key_anchor(node);
- printf(" &%.*s", (int)ka.len, ka.str);
- }
- if(p.has_key_tag(node))
- {
- csubstr kt = p.key_tag(node);
- csubstr k = p.key(node);
- printf(" %.*s '%.*s'", (int)kt.len, kt.str, (int)k.len, k.str);
- }
- else
- {
- csubstr k = p.key(node);
- printf(" '%.*s'", (int)k.len, k.str);
- }
- }
- else
- {
- RYML_ASSERT( ! p.has_key_tag(node));
- }
- if(p.has_val(node))
- {
- if(p.has_val_tag(node))
- {
- csubstr vt = p.val_tag(node);
- csubstr v = p.val(node);
- printf(" %.*s '%.*s'", (int)vt.len, vt.str, (int)v.len, v.str);
- }
- else
- {
- csubstr v = p.val(node);
- printf(" '%.*s'", (int)v.len, v.str);
- }
- }
- else
- {
- if(p.has_val_tag(node))
- {
- csubstr vt = p.val_tag(node);
- printf(" %.*s", (int)vt.len, vt.str);
- }
- }
- if(p.has_val_anchor(node))
- {
- auto &a = p.val_anchor(node);
- printf(" valanchor='&%.*s'", (int)a.len, a.str);
- }
- printf(" (%zd sibs)", p.num_siblings(node));
-
- ++count;
-
- if(p.is_container(node))
- {
- printf(" %zd children:\n", p.num_children(node));
- if(print_children)
- {
- for(size_t i = p.first_child(node); i != NONE; i = p.next_sibling(i))
- {
- count = print_node(p, i, level+1, count, print_children);
- }
- }
- }
- else
- {
- printf("\n");
- }
-
- return count;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-inline void print_node(ConstNodeRef const& p, int level=0)
-{
- print_node(*p.tree(), p.id(), level, 0, true);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-inline size_t print_tree(Tree const& p, size_t node=NONE)
-{
- printf("--------------------------------------\n");
- size_t ret = 0;
- if(!p.empty())
- {
- if(node == NONE)
- node = p.root_id();
- ret = print_node(p, node, 0, 0, true);
- }
- printf("#nodes=%zd vs #printed=%zd\n", p.size(), ret);
- printf("--------------------------------------\n");
- return ret;
-}
-
-
-} /* namespace yml */
-} /* namespace c4 */
-
-
-#endif /* C4_YML_DETAIL_PRINT_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/detail/stack.hpp b/thirdparty/ryml/src/c4/yml/detail/stack.hpp
deleted file mode 100644
index 95677ae27..000000000
--- a/thirdparty/ryml/src/c4/yml/detail/stack.hpp
+++ /dev/null
@@ -1,274 +0,0 @@
-#ifndef _C4_YML_DETAIL_STACK_HPP_
-#define _C4_YML_DETAIL_STACK_HPP_
-
-#ifndef _C4_YML_COMMON_HPP_
-#include "../common.hpp"
-#endif
-
-#ifdef RYML_DBG
-# include <type_traits>
-#endif
-
-#include <string.h>
-
-namespace c4 {
-namespace yml {
-namespace detail {
-
-/** A lightweight contiguous stack with SSO. This avoids a dependency on std. */
-template<class T, size_t N=16>
-class stack
-{
- static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
- static_assert(std::is_trivially_destructible<T>::value, "T must be trivially destructible");
-
- enum : size_t { sso_size = N };
-
-public:
-
- T m_buf[N];
- T * m_stack;
- size_t m_size;
- size_t m_capacity;
- Callbacks m_callbacks;
-
-public:
-
- constexpr static bool is_contiguous() { return true; }
-
- stack(Callbacks const& cb)
- : m_buf()
- , m_stack(m_buf)
- , m_size(0)
- , m_capacity(N)
- , m_callbacks(cb) {}
- stack() : stack(get_callbacks()) {}
- ~stack()
- {
- _free();
- }
-
- stack(stack const& that) noexcept : stack(that.m_callbacks)
- {
- resize(that.m_size);
- _cp(&that);
- }
-
- stack(stack &&that) noexcept : stack(that.m_callbacks)
- {
- _mv(&that);
- }
-
- stack& operator= (stack const& that) noexcept
- {
- _cb(that.m_callbacks);
- resize(that.m_size);
- _cp(&that);
- return *this;
- }
-
- stack& operator= (stack &&that) noexcept
- {
- _cb(that.m_callbacks);
- _mv(&that);
- return *this;
- }
-
-public:
-
- size_t size() const { return m_size; }
- size_t empty() const { return m_size == 0; }
- size_t capacity() const { return m_capacity; }
-
- void clear()
- {
- m_size = 0;
- }
-
- void resize(size_t sz)
- {
- reserve(sz);
- m_size = sz;
- }
-
- void reserve(size_t sz);
-
- void push(T const& C4_RESTRICT n)
- {
- RYML_ASSERT((const char*)&n + sizeof(T) < (const char*)m_stack || &n > m_stack + m_capacity);
- if(m_size == m_capacity)
- {
- size_t cap = m_capacity == 0 ? N : 2 * m_capacity;
- reserve(cap);
- }
- m_stack[m_size] = n;
- ++m_size;
- }
-
- void push_top()
- {
- RYML_ASSERT(m_size > 0);
- if(m_size == m_capacity)
- {
- size_t cap = m_capacity == 0 ? N : 2 * m_capacity;
- reserve(cap);
- }
- m_stack[m_size] = m_stack[m_size - 1];
- ++m_size;
- }
-
- T const& C4_RESTRICT pop()
- {
- RYML_ASSERT(m_size > 0);
- --m_size;
- return m_stack[m_size];
- }
-
- C4_ALWAYS_INLINE T const& C4_RESTRICT top() const { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }
- C4_ALWAYS_INLINE T & C4_RESTRICT top() { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }
-
- C4_ALWAYS_INLINE T const& C4_RESTRICT bottom() const { RYML_ASSERT(m_size > 0); return m_stack[0]; }
- C4_ALWAYS_INLINE T & C4_RESTRICT bottom() { RYML_ASSERT(m_size > 0); return m_stack[0]; }
-
- C4_ALWAYS_INLINE T const& C4_RESTRICT top(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }
- C4_ALWAYS_INLINE T & C4_RESTRICT top(size_t i) { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }
-
- C4_ALWAYS_INLINE T const& C4_RESTRICT bottom(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }
- C4_ALWAYS_INLINE T & C4_RESTRICT bottom(size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }
-
- C4_ALWAYS_INLINE T const& C4_RESTRICT operator[](size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }
- C4_ALWAYS_INLINE T & C4_RESTRICT operator[](size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }
-
-public:
-
- using iterator = T *;
- using const_iterator = T const *;
-
- iterator begin() { return m_stack; }
- iterator end () { return m_stack + m_size; }
-
- const_iterator begin() const { return (const_iterator)m_stack; }
- const_iterator end () const { return (const_iterator)m_stack + m_size; }
-
-public:
- void _free();
- void _cp(stack const* C4_RESTRICT that);
- void _mv(stack * that);
- void _cb(Callbacks const& cb);
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-template<class T, size_t N>
-void stack<T, N>::reserve(size_t sz)
-{
- if(sz <= m_size)
- return;
- if(sz <= N)
- {
- m_stack = m_buf;
- m_capacity = N;
- return;
- }
- T *buf = (T*) m_callbacks.m_allocate(sz * sizeof(T), m_stack, m_callbacks.m_user_data);
- memcpy(buf, m_stack, m_size * sizeof(T));
- if(m_stack != m_buf)
- {
- m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);
- }
- m_stack = buf;
- m_capacity = sz;
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<class T, size_t N>
-void stack<T, N>::_free()
-{
- RYML_ASSERT(m_stack != nullptr); // this structure cannot be memset() to zero
- if(m_stack != m_buf)
- {
- m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);
- m_stack = m_buf;
- m_size = N;
- m_capacity = N;
- }
- else
- {
- RYML_ASSERT(m_capacity == N);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<class T, size_t N>
-void stack<T, N>::_cp(stack const* C4_RESTRICT that)
-{
- if(that->m_stack != that->m_buf)
- {
- RYML_ASSERT(that->m_capacity > N);
- RYML_ASSERT(that->m_size <= that->m_capacity);
- }
- else
- {
- RYML_ASSERT(that->m_capacity <= N);
- RYML_ASSERT(that->m_size <= that->m_capacity);
- }
- memcpy(m_stack, that->m_stack, that->m_size * sizeof(T));
- m_size = that->m_size;
- m_capacity = that->m_size < N ? N : that->m_size;
- m_callbacks = that->m_callbacks;
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<class T, size_t N>
-void stack<T, N>::_mv(stack * that)
-{
- if(that->m_stack != that->m_buf)
- {
- RYML_ASSERT(that->m_capacity > N);
- RYML_ASSERT(that->m_size <= that->m_capacity);
- m_stack = that->m_stack;
- }
- else
- {
- RYML_ASSERT(that->m_capacity <= N);
- RYML_ASSERT(that->m_size <= that->m_capacity);
- memcpy(m_buf, that->m_buf, that->m_size * sizeof(T));
- m_stack = m_buf;
- }
- m_size = that->m_size;
- m_capacity = that->m_capacity;
- m_callbacks = that->m_callbacks;
- // make sure no deallocation happens on destruction
- RYML_ASSERT(that->m_stack != m_buf);
- that->m_stack = that->m_buf;
- that->m_capacity = N;
- that->m_size = 0;
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<class T, size_t N>
-void stack<T, N>::_cb(Callbacks const& cb)
-{
- if(cb != m_callbacks)
- {
- _free();
- m_callbacks = cb;
- }
-}
-
-} // namespace detail
-} // namespace yml
-} // namespace c4
-
-#endif /* _C4_YML_DETAIL_STACK_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/emit.def.hpp b/thirdparty/ryml/src/c4/yml/emit.def.hpp
deleted file mode 100644
index d262a9e2a..000000000
--- a/thirdparty/ryml/src/c4/yml/emit.def.hpp
+++ /dev/null
@@ -1,960 +0,0 @@
-#ifndef _C4_YML_EMIT_DEF_HPP_
-#define _C4_YML_EMIT_DEF_HPP_
-
-#ifndef _C4_YML_EMIT_HPP_
-#include "c4/yml/emit.hpp"
-#endif
-
-namespace c4 {
-namespace yml {
-
-template<class Writer>
-substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess)
-{
- if(t.empty())
- {
- _RYML_CB_ASSERT(t.callbacks(), id == NONE);
- return {};
- }
- _RYML_CB_CHECK(t.callbacks(), id < t.size());
- m_tree = &t;
- if(type == EMIT_YAML)
- _emit_yaml(id);
- else if(type == EMIT_JSON)
- _do_visit_json(id);
- else
- _RYML_CB_ERR(m_tree->callbacks(), "unknown emit type");
- return this->Writer::_get(error_on_excess);
-}
-
-template<class Writer>
-substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, bool error_on_excess)
-{
- if(t.empty())
- return {};
- return this->emit_as(type, t, t.root_id(), error_on_excess);
-}
-
-template<class Writer>
-substr Emitter<Writer>::emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess)
-{
- _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
- return this->emit_as(type, *n.tree(), n.id(), error_on_excess);
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<class Writer>
-void Emitter<Writer>::_emit_yaml(size_t id)
-{
- // save branches in the visitor by doing the initial stream/doc
- // logic here, sparing the need to check stream/val/keyval inside
- // the visitor functions
- auto dispatch = [this](size_t node){
- NodeType ty = m_tree->type(node);
- if(ty.marked_flow_sl())
- _do_visit_flow_sl(node, 0);
- else if(ty.marked_flow_ml())
- _do_visit_flow_ml(node, 0);
- else
- {
- _do_visit_block(node, 0);
- }
- };
- if(!m_tree->is_root(id))
- {
- if(m_tree->is_container(id) && !m_tree->type(id).marked_flow())
- {
- size_t ilevel = 0;
- if(m_tree->has_key(id))
- {
- this->Writer::_do_write(m_tree->key(id));
- this->Writer::_do_write(":\n");
- ++ilevel;
- }
- _do_visit_block_container(id, ilevel, ilevel);
- return;
- }
- }
-
- auto *btd = m_tree->tag_directives().b;
- auto *etd = m_tree->tag_directives().e;
- auto write_tag_directives = [&btd, etd, this](size_t next_node){
- auto end = btd;
- while(end < etd)
- {
- if(end->next_node_id > next_node)
- break;
- ++end;
- }
- for( ; btd != end; ++btd)
- {
- if(next_node != m_tree->first_child(m_tree->parent(next_node)))
- this->Writer::_do_write("...\n");
- this->Writer::_do_write("%TAG ");
- this->Writer::_do_write(btd->handle);
- this->Writer::_do_write(' ');
- this->Writer::_do_write(btd->prefix);
- this->Writer::_do_write('\n');
- }
- };
- if(m_tree->is_stream(id))
- {
- if(m_tree->first_child(id) != NONE)
- write_tag_directives(m_tree->first_child(id));
- for(size_t child = m_tree->first_child(id); child != NONE; child = m_tree->next_sibling(child))
- {
- dispatch(child);
- if(m_tree->next_sibling(child) != NONE)
- write_tag_directives(m_tree->next_sibling(child));
- }
- }
- else if(m_tree->is_container(id))
- {
- dispatch(id);
- }
- else if(m_tree->is_doc(id))
- {
- _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_container(id)); // checked above
- _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_val(id)); // so it must be a val
- _write_doc(id);
- }
- else if(m_tree->is_keyval(id))
- {
- _writek(id, 0);
- this->Writer::_do_write(": ");
- _writev(id, 0);
- if(!m_tree->type(id).marked_flow())
- this->Writer::_do_write('\n');
- }
- else if(m_tree->is_val(id))
- {
- //this->Writer::_do_write("- ");
- _writev(id, 0);
- if(!m_tree->type(id).marked_flow())
- this->Writer::_do_write('\n');
- }
- else if(m_tree->type(id) == NOTYPE)
- {
- ;
- }
- else
- {
- _RYML_CB_ERR(m_tree->callbacks(), "unknown type");
- }
-}
-
-template<class Writer>
-void Emitter<Writer>::_write_doc(size_t id)
-{
- RYML_ASSERT(m_tree->is_doc(id));
- if(!m_tree->is_root(id))
- {
- RYML_ASSERT(m_tree->is_stream(m_tree->parent(id)));
- this->Writer::_do_write("---");
- }
- if(!m_tree->has_val(id)) // this is more frequent
- {
- if(m_tree->has_val_tag(id))
- {
- if(!m_tree->is_root(id))
- this->Writer::_do_write(' ');
- _write_tag(m_tree->val_tag(id));
- }
- if(m_tree->has_val_anchor(id))
- {
- if(!m_tree->is_root(id))
- this->Writer::_do_write(' ');
- this->Writer::_do_write('&');
- this->Writer::_do_write(m_tree->val_anchor(id));
- }
- }
- else // docval
- {
- RYML_ASSERT(m_tree->has_val(id));
- RYML_ASSERT(!m_tree->has_key(id));
- if(!m_tree->is_root(id))
- this->Writer::_do_write(' ');
- _writev(id, 0);
- }
- this->Writer::_do_write('\n');
-}
-
-template<class Writer>
-void Emitter<Writer>::_do_visit_flow_sl(size_t node, size_t ilevel)
-{
- RYML_ASSERT(!m_tree->is_stream(node));
- RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node));
- RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
-
- if(m_tree->is_doc(node))
- {
- _write_doc(node);
- if(!m_tree->has_children(node))
- return;
- }
- else if(m_tree->is_container(node))
- {
- RYML_ASSERT(m_tree->is_map(node) || m_tree->is_seq(node));
-
- bool spc = false; // write a space
-
- if(m_tree->has_key(node))
- {
- _writek(node, ilevel);
- this->Writer::_do_write(':');
- spc = true;
- }
-
- if(m_tree->has_val_tag(node))
- {
- if(spc)
- this->Writer::_do_write(' ');
- _write_tag(m_tree->val_tag(node));
- spc = true;
- }
-
- if(m_tree->has_val_anchor(node))
- {
- if(spc)
- this->Writer::_do_write(' ');
- this->Writer::_do_write('&');
- this->Writer::_do_write(m_tree->val_anchor(node));
- spc = true;
- }
-
- if(spc)
- this->Writer::_do_write(' ');
-
- if(m_tree->is_map(node))
- {
- this->Writer::_do_write('{');
- }
- else
- {
- _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node));
- this->Writer::_do_write('[');
- }
- } // container
-
- for(size_t child = m_tree->first_child(node), count = 0; child != NONE; child = m_tree->next_sibling(child))
- {
- if(count++)
- this->Writer::_do_write(',');
- if(m_tree->is_keyval(child))
- {
- _writek(child, ilevel);
- this->Writer::_do_write(": ");
- _writev(child, ilevel);
- }
- else if(m_tree->is_val(child))
- {
- _writev(child, ilevel);
- }
- else
- {
- // with single-line flow, we can never go back to block
- _do_visit_flow_sl(child, ilevel + 1);
- }
- }
-
- if(m_tree->is_map(node))
- {
- this->Writer::_do_write('}');
- }
- else if(m_tree->is_seq(node))
- {
- this->Writer::_do_write(']');
- }
-}
-
-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*/);
-}
-
-template<class Writer>
-void Emitter<Writer>::_do_visit_block_container(size_t node, size_t next_level, size_t do_indent)
-{
- RepC ind = indent_to(do_indent * next_level);
-
- if(m_tree->is_seq(node))
- {
- for(size_t child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child))
- {
- _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->has_key(child));
- if(m_tree->is_val(child))
- {
- this->Writer::_do_write(ind);
- this->Writer::_do_write("- ");
- _writev(child, next_level);
- this->Writer::_do_write('\n');
- }
- else
- {
- _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(child));
- NodeType ty = m_tree->type(child);
- if(ty.marked_flow_sl())
- {
- this->Writer::_do_write(ind);
- this->Writer::_do_write("- ");
- _do_visit_flow_sl(child, 0u);
- this->Writer::_do_write('\n');
- }
- else if(ty.marked_flow_ml())
- {
- this->Writer::_do_write(ind);
- this->Writer::_do_write("- ");
- _do_visit_flow_ml(child, next_level, do_indent);
- this->Writer::_do_write('\n');
- }
- else
- {
- _do_visit_block(child, next_level, do_indent);
- }
- }
- do_indent = true;
- ind = indent_to(do_indent * next_level);
- }
- }
- else // map
- {
- _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node));
- for(size_t ich = m_tree->first_child(node); ich != NONE; ich = m_tree->next_sibling(ich))
- {
- _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_key(ich));
- if(m_tree->is_keyval(ich))
- {
- this->Writer::_do_write(ind);
- _writek(ich, next_level);
- this->Writer::_do_write(": ");
- _writev(ich, next_level);
- this->Writer::_do_write('\n');
- }
- else
- {
- _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(ich));
- NodeType ty = m_tree->type(ich);
- if(ty.marked_flow_sl())
- {
- this->Writer::_do_write(ind);
- _do_visit_flow_sl(ich, 0u);
- this->Writer::_do_write('\n');
- }
- else if(ty.marked_flow_ml())
- {
- this->Writer::_do_write(ind);
- _do_visit_flow_ml(ich, 0u);
- this->Writer::_do_write('\n');
- }
- else
- {
- _do_visit_block(ich, next_level, do_indent);
- }
- }
- do_indent = true;
- ind = indent_to(do_indent * next_level);
- }
- }
-}
-
-template<class Writer>
-void Emitter<Writer>::_do_visit_block(size_t node, size_t ilevel, size_t do_indent)
-{
- RYML_ASSERT(!m_tree->is_stream(node));
- RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node));
- RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
- RepC ind = indent_to(do_indent * ilevel);
-
- if(m_tree->is_doc(node))
- {
- _write_doc(node);
- if(!m_tree->has_children(node))
- return;
- }
- else if(m_tree->is_container(node))
- {
- RYML_ASSERT(m_tree->is_map(node) || m_tree->is_seq(node));
-
- bool spc = false; // write a space
- bool nl = false; // write a newline
-
- if(m_tree->has_key(node))
- {
- this->Writer::_do_write(ind);
- _writek(node, ilevel);
- this->Writer::_do_write(':');
- spc = true;
- }
- else if(!m_tree->is_root(node))
- {
- this->Writer::_do_write(ind);
- this->Writer::_do_write('-');
- spc = true;
- }
-
- if(m_tree->has_val_tag(node))
- {
- if(spc)
- this->Writer::_do_write(' ');
- _write_tag(m_tree->val_tag(node));
- spc = true;
- nl = true;
- }
-
- if(m_tree->has_val_anchor(node))
- {
- if(spc)
- this->Writer::_do_write(' ');
- this->Writer::_do_write('&');
- this->Writer::_do_write(m_tree->val_anchor(node));
- spc = true;
- nl = true;
- }
-
- if(m_tree->has_children(node))
- {
- if(m_tree->has_key(node))
- nl = true;
- else
- if(!m_tree->is_root(node) && !nl)
- spc = true;
- }
- else
- {
- if(m_tree->is_seq(node))
- this->Writer::_do_write(" []\n");
- else if(m_tree->is_map(node))
- this->Writer::_do_write(" {}\n");
- return;
- }
-
- if(spc && !nl)
- this->Writer::_do_write(' ');
-
- do_indent = 0;
- if(nl)
- {
- this->Writer::_do_write('\n');
- do_indent = 1;
- }
- } // container
-
- size_t next_level = ilevel + 1;
- if(m_tree->is_root(node) || m_tree->is_doc(node))
- next_level = ilevel; // do not indent at top level
-
- _do_visit_block_container(node, next_level, do_indent);
-}
-
-template<class Writer>
-void Emitter<Writer>::_do_visit_json(size_t id)
-{
- _RYML_CB_CHECK(m_tree->callbacks(), !m_tree->is_stream(id)); // JSON does not have streams
- if(m_tree->is_keyval(id))
- {
- _writek_json(id);
- this->Writer::_do_write(": ");
- _writev_json(id);
- }
- else if(m_tree->is_val(id))
- {
- _writev_json(id);
- }
- else if(m_tree->is_container(id))
- {
- if(m_tree->has_key(id))
- {
- _writek_json(id);
- this->Writer::_do_write(": ");
- }
- if(m_tree->is_seq(id))
- this->Writer::_do_write('[');
- else if(m_tree->is_map(id))
- this->Writer::_do_write('{');
- } // container
-
- for(size_t ich = m_tree->first_child(id); ich != NONE; ich = m_tree->next_sibling(ich))
- {
- if(ich != m_tree->first_child(id))
- this->Writer::_do_write(',');
- _do_visit_json(ich);
- }
-
- if(m_tree->is_seq(id))
- this->Writer::_do_write(']');
- else if(m_tree->is_map(id))
- this->Writer::_do_write('}');
-}
-
-template<class Writer>
-void Emitter<Writer>::_write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t ilevel)
-{
- if( ! sc.tag.empty())
- {
- _write_tag(sc.tag);
- this->Writer::_do_write(' ');
- }
- if(flags.has_anchor())
- {
- RYML_ASSERT(flags.is_ref() != flags.has_anchor());
- RYML_ASSERT( ! sc.anchor.empty());
- this->Writer::_do_write('&');
- this->Writer::_do_write(sc.anchor);
- this->Writer::_do_write(' ');
- }
- else if(flags.is_ref())
- {
- if(sc.anchor != "<<")
- this->Writer::_do_write('*');
- this->Writer::_do_write(sc.anchor);
- return;
- }
-
- // ensure the style flags only have one of KEY or VAL
- _RYML_CB_ASSERT(m_tree->callbacks(), ((flags & (_WIP_KEY_STYLE|_WIP_VAL_STYLE)) == 0) || (((flags&_WIP_KEY_STYLE) == 0) != ((flags&_WIP_VAL_STYLE) == 0)));
-
- auto style_marks = flags & (_WIP_KEY_STYLE|_WIP_VAL_STYLE);
- if(style_marks & (_WIP_KEY_LITERAL|_WIP_VAL_LITERAL))
- {
- _write_scalar_literal(sc.scalar, ilevel, flags.has_key());
- }
- else if(style_marks & (_WIP_KEY_FOLDED|_WIP_VAL_FOLDED))
- {
- _write_scalar_folded(sc.scalar, ilevel, flags.has_key());
- }
- else if(style_marks & (_WIP_KEY_SQUO|_WIP_VAL_SQUO))
- {
- _write_scalar_squo(sc.scalar, ilevel);
- }
- else if(style_marks & (_WIP_KEY_DQUO|_WIP_VAL_DQUO))
- {
- _write_scalar_dquo(sc.scalar, ilevel);
- }
- else if(style_marks & (_WIP_KEY_PLAIN|_WIP_VAL_PLAIN))
- {
- _write_scalar_plain(sc.scalar, ilevel);
- }
- else if(!style_marks)
- {
- size_t first_non_nl = sc.scalar.first_not_of('\n');
- bool all_newlines = first_non_nl == npos;
- bool has_leading_ws = (!all_newlines) && sc.scalar.sub(first_non_nl).begins_with_any(" \t");
- bool do_literal = ((!sc.scalar.empty() && all_newlines) || (has_leading_ws && !sc.scalar.trim(' ').empty()));
- if(do_literal)
- {
- _write_scalar_literal(sc.scalar, ilevel, flags.has_key(), /*explicit_indentation*/has_leading_ws);
- }
- else
- {
- for(size_t i = 0; i < sc.scalar.len; ++i)
- {
- if(sc.scalar.str[i] == '\n')
- {
- _write_scalar_literal(sc.scalar, ilevel, flags.has_key(), /*explicit_indentation*/has_leading_ws);
- goto wrote_special;
- }
- // todo: check for escaped characters requiring double quotes
- }
- _write_scalar(sc.scalar, flags.is_quoted());
- wrote_special:
- ;
- }
- }
- else
- {
- _RYML_CB_ERR(m_tree->callbacks(), "not implemented");
- }
-}
-template<class Writer>
-void Emitter<Writer>::_write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags)
-{
- if(C4_UNLIKELY( ! sc.tag.empty()))
- _RYML_CB_ERR(m_tree->callbacks(), "JSON does not have tags");
- if(C4_UNLIKELY(flags.has_anchor()))
- _RYML_CB_ERR(m_tree->callbacks(), "JSON does not have anchors");
- _write_scalar_json(sc.scalar, flags.has_key(), flags.is_quoted());
-}
-
-#define _rymlindent_nextline() for(size_t lv = 0; lv < ilevel+1; ++lv) { this->Writer::_do_write(' '); this->Writer::_do_write(' '); }
-
-template<class Writer>
-void Emitter<Writer>::_write_scalar_literal(csubstr s, size_t ilevel, bool explicit_key, bool explicit_indentation)
-{
- if(explicit_key)
- this->Writer::_do_write("? ");
- csubstr trimmed = s.trimr("\n\r");
- size_t numnewlines_at_end = s.len - trimmed.len - s.sub(trimmed.len).count('\r');
- //
- if(!explicit_indentation)
- this->Writer::_do_write('|');
- else
- this->Writer::_do_write("|2");
- //
- if(numnewlines_at_end > 1 || (trimmed.len == 0 && s.len > 0)/*only newlines*/)
- this->Writer::_do_write("+\n");
- else if(numnewlines_at_end == 1)
- this->Writer::_do_write('\n');
- else
- this->Writer::_do_write("-\n");
- //
- if(trimmed.len)
- {
- size_t pos = 0; // tracks the last character that was already written
- for(size_t i = 0; i < trimmed.len; ++i)
- {
- if(trimmed[i] != '\n')
- continue;
- // write everything up to this point
- csubstr since_pos = trimmed.range(pos, i+1); // include the newline
- _rymlindent_nextline()
- this->Writer::_do_write(since_pos);
- pos = i+1; // already written
- }
- if(pos < trimmed.len)
- {
- _rymlindent_nextline()
- this->Writer::_do_write(trimmed.sub(pos));
- }
- if(numnewlines_at_end)
- {
- this->Writer::_do_write('\n');
- --numnewlines_at_end;
- }
- }
- for(size_t i = 0; i < numnewlines_at_end; ++i)
- {
- _rymlindent_nextline()
- if(i+1 < numnewlines_at_end || explicit_key)
- this->Writer::_do_write('\n');
- }
- if(explicit_key && !numnewlines_at_end)
- this->Writer::_do_write('\n');
-}
-
-template<class Writer>
-void Emitter<Writer>::_write_scalar_folded(csubstr s, size_t ilevel, bool explicit_key)
-{
- if(explicit_key)
- {
- this->Writer::_do_write("? ");
- }
- RYML_ASSERT(s.find("\r") == csubstr::npos);
- csubstr trimmed = s.trimr('\n');
- size_t numnewlines_at_end = s.len - trimmed.len;
- if(numnewlines_at_end == 0)
- {
- this->Writer::_do_write(">-\n");
- }
- else if(numnewlines_at_end == 1)
- {
- this->Writer::_do_write(">\n");
- }
- else if(numnewlines_at_end > 1)
- {
- this->Writer::_do_write(">+\n");
- }
- if(trimmed.len)
- {
- size_t pos = 0; // tracks the last character that was already written
- for(size_t i = 0; i < trimmed.len; ++i)
- {
- if(trimmed[i] != '\n')
- continue;
- // write everything up to this point
- csubstr since_pos = trimmed.range(pos, i+1); // include the newline
- pos = i+1; // because of the newline
- _rymlindent_nextline()
- this->Writer::_do_write(since_pos);
- this->Writer::_do_write('\n'); // write the newline twice
- }
- if(pos < trimmed.len)
- {
- _rymlindent_nextline()
- this->Writer::_do_write(trimmed.sub(pos));
- }
- if(numnewlines_at_end)
- {
- this->Writer::_do_write('\n');
- --numnewlines_at_end;
- }
- }
- for(size_t i = 0; i < numnewlines_at_end; ++i)
- {
- _rymlindent_nextline()
- if(i+1 < numnewlines_at_end || explicit_key)
- this->Writer::_do_write('\n');
- }
- if(explicit_key && !numnewlines_at_end)
- this->Writer::_do_write('\n');
-}
-
-template<class Writer>
-void Emitter<Writer>::_write_scalar_squo(csubstr s, size_t ilevel)
-{
- size_t pos = 0; // tracks the last character that was already written
- this->Writer::_do_write('\'');
- for(size_t i = 0; i < s.len; ++i)
- {
- if(s[i] == '\n')
- {
- csubstr sub = s.range(pos, i+1);
- this->Writer::_do_write(sub); // write everything up to (including) this char
- this->Writer::_do_write('\n'); // write the character again
- if(i + 1 < s.len)
- _rymlindent_nextline() // indent the next line
- pos = i+1;
- }
- else if(s[i] == '\'')
- {
- csubstr sub = s.range(pos, i+1);
- this->Writer::_do_write(sub); // write everything up to (including) this char
- this->Writer::_do_write('\''); // write the character again
- pos = i+1;
- }
- }
- // write missing characters at the end of the string
- if(pos < s.len)
- this->Writer::_do_write(s.sub(pos));
- this->Writer::_do_write('\'');
-}
-
-template<class Writer>
-void Emitter<Writer>::_write_scalar_dquo(csubstr s, size_t ilevel)
-{
- size_t pos = 0; // tracks the last character that was already written
- this->Writer::_do_write('"');
- for(size_t i = 0; i < s.len; ++i)
- {
- const char curr = s.str[i];
- if(curr == '"' || curr == '\\')
- {
- csubstr sub = s.range(pos, i);
- this->Writer::_do_write(sub); // write everything up to (excluding) this char
- this->Writer::_do_write('\\'); // write the escape
- this->Writer::_do_write(curr); // write the char
- pos = i+1;
- }
- else if(s[i] == '\n')
- {
- csubstr sub = s.range(pos, i+1);
- this->Writer::_do_write(sub); // write everything up to (including) this newline
- this->Writer::_do_write('\n'); // write the newline again
- if(i + 1 < s.len)
- _rymlindent_nextline() // indent the next line
- pos = i+1;
- if(i+1 < s.len) // escape leading whitespace after the newline
- {
- const char next = s.str[i+1];
- if(next == ' ' || next == '\t')
- this->Writer::_do_write('\\');
- }
- }
- else if(curr == ' ' || curr == '\t')
- {
- // escape trailing whitespace before a newline
- size_t next = s.first_not_of(" \t\r", i);
- if(next != npos && s[next] == '\n')
- {
- csubstr sub = s.range(pos, i);
- this->Writer::_do_write(sub); // write everything up to (excluding) this char
- this->Writer::_do_write('\\'); // escape the whitespace
- pos = i;
- }
- }
- else if(C4_UNLIKELY(curr == '\r'))
- {
- csubstr sub = s.range(pos, i);
- this->Writer::_do_write(sub); // write everything up to (excluding) this char
- this->Writer::_do_write("\\r"); // write the escaped char
- pos = i+1;
- }
- }
- // write missing characters at the end of the string
- if(pos < s.len)
- {
- csubstr sub = s.sub(pos);
- this->Writer::_do_write(sub);
- }
- this->Writer::_do_write('"');
-}
-
-template<class Writer>
-void Emitter<Writer>::_write_scalar_plain(csubstr s, size_t ilevel)
-{
- size_t pos = 0; // tracks the last character that was already written
- for(size_t i = 0; i < s.len; ++i)
- {
- const char curr = s.str[i];
- if(curr == '\n')
- {
- csubstr sub = s.range(pos, i+1);
- this->Writer::_do_write(sub); // write everything up to (including) this newline
- this->Writer::_do_write('\n'); // write the newline again
- if(i + 1 < s.len)
- _rymlindent_nextline() // indent the next line
- pos = i+1;
- }
- }
- // write missing characters at the end of the string
- if(pos < s.len)
- {
- csubstr sub = s.sub(pos);
- this->Writer::_do_write(sub);
- }
-}
-
-#undef _rymlindent_nextline
-
-template<class Writer>
-void Emitter<Writer>::_write_scalar(csubstr s, bool was_quoted)
-{
- // this block of code needed to be moved to before the needs_quotes
- // assignment to work around a g++ optimizer bug where (s.str != nullptr)
- // was evaluated as true even if s.str was actually a nullptr (!!!)
- if(s.len == size_t(0))
- {
- if(was_quoted || s.str != nullptr)
- this->Writer::_do_write("''");
- return;
- }
-
- const bool needs_quotes = (
- was_quoted
- ||
- (
- ( ! s.is_number())
- &&
- (
- // has leading whitespace
- // looks like reference or anchor
- // would be treated as a directive
- // see https://www.yaml.info/learn/quote.html#noplain
- s.begins_with_any(" \n\t\r*&%@`")
- ||
- s.begins_with("<<")
- ||
- // has trailing whitespace
- s.ends_with_any(" \n\t\r")
- ||
- // has special chars
- (s.first_of("#:-?,\n{}[]'\"") != npos)
- )
- )
- );
-
- if( ! needs_quotes)
- {
- this->Writer::_do_write(s);
- }
- else
- {
- const bool has_dquotes = s.first_of( '"') != npos;
- const bool has_squotes = s.first_of('\'') != npos;
- if(!has_squotes && has_dquotes)
- {
- this->Writer::_do_write('\'');
- this->Writer::_do_write(s);
- this->Writer::_do_write('\'');
- }
- else if(has_squotes && !has_dquotes)
- {
- RYML_ASSERT(s.count('\n') == 0);
- this->Writer::_do_write('"');
- this->Writer::_do_write(s);
- this->Writer::_do_write('"');
- }
- else
- {
- _write_scalar_squo(s, /*FIXME FIXME FIXME*/0);
- }
- }
-}
-template<class Writer>
-void Emitter<Writer>::_write_scalar_json(csubstr s, bool as_key, bool use_quotes)
-{
- if((!use_quotes)
- // json keys require quotes
- && (!as_key)
- && (
- // do not quote special cases
- (s == "true" || s == "false" || s == "null")
- || (
- // do not quote numbers
- (s.is_number()
- && (
- // quote integral numbers if they have a leading 0
- // https://github.com/biojppm/rapidyaml/issues/291
- (!(s.len > 1 && s.begins_with('0')))
- // do not quote reals with leading 0
- // https://github.com/biojppm/rapidyaml/issues/313
- || (s.find('.') != csubstr::npos) ))
- )
- )
- )
- {
- this->Writer::_do_write(s);
- }
- else
- {
- size_t pos = 0;
- this->Writer::_do_write('"');
- for(size_t i = 0; i < s.len; ++i)
- {
- switch(s.str[i])
- {
- case '"':
- this->Writer ::_do_write(s.range(pos, i));
- this->Writer ::_do_write("\\\"");
- pos = i + 1;
- break;
- case '\n':
- this->Writer ::_do_write(s.range(pos, i));
- this->Writer ::_do_write("\\n");
- pos = i + 1;
- break;
- case '\t':
- this->Writer ::_do_write(s.range(pos, i));
- this->Writer ::_do_write("\\t");
- pos = i + 1;
- break;
- case '\\':
- this->Writer ::_do_write(s.range(pos, i));
- this->Writer ::_do_write("\\\\");
- pos = i + 1;
- break;
- case '\r':
- this->Writer ::_do_write(s.range(pos, i));
- this->Writer ::_do_write("\\r");
- pos = i + 1;
- break;
- case '\b':
- this->Writer ::_do_write(s.range(pos, i));
- this->Writer ::_do_write("\\b");
- pos = i + 1;
- break;
- case '\f':
- this->Writer ::_do_write(s.range(pos, i));
- this->Writer ::_do_write("\\f");
- pos = i + 1;
- break;
- }
- }
- if(pos < s.len)
- {
- csubstr sub = s.sub(pos);
- this->Writer::_do_write(sub);
- }
- this->Writer::_do_write('"');
- }
-}
-
-} // namespace yml
-} // namespace c4
-
-#endif /* _C4_YML_EMIT_DEF_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/emit.hpp b/thirdparty/ryml/src/c4/yml/emit.hpp
deleted file mode 100644
index c7cdd2a1a..000000000
--- a/thirdparty/ryml/src/c4/yml/emit.hpp
+++ /dev/null
@@ -1,490 +0,0 @@
-#ifndef _C4_YML_EMIT_HPP_
-#define _C4_YML_EMIT_HPP_
-
-#ifndef _C4_YML_WRITER_HPP_
-#include "./writer.hpp"
-#endif
-
-#ifndef _C4_YML_TREE_HPP_
-#include "./tree.hpp"
-#endif
-
-#ifndef _C4_YML_NODE_HPP_
-#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_EMITRS \
- RYML_DEPRECATED("use emitrs_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-namespace c4 {
-namespace yml {
-
-template<class Writer> class Emitter;
-
-template<class OStream>
-using EmitterOStream = Emitter<WriterOStream<OStream>>;
-using EmitterFile = Emitter<WriterFile>;
-using EmitterBuf = Emitter<WriterBuf>;
-
-typedef enum {
- EMIT_YAML = 0,
- EMIT_JSON = 1
-} 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()) {}
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-template<class Writer>
-class Emitter : public Writer
-{
-public:
-
- using Writer::Writer;
-
- /** 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.
- *
- * When writing to a file, the returned substr will be null, but its
- * length will be set to the number of bytes written. */
- 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);
- /** emit the given node */
- substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true);
-
-private:
-
- Tree const* C4_RESTRICT m_tree;
-
- void _emit_yaml(size_t id);
- void _do_visit_flow_sl(size_t id, size_t ilevel=0);
- void _do_visit_flow_ml(size_t id, size_t ilevel=0, size_t do_indent=1);
- void _do_visit_block(size_t id, size_t ilevel=0, size_t do_indent=1);
- void _do_visit_block_container(size_t id, size_t next_level, size_t do_indent);
- void _do_visit_json(size_t id);
-
-private:
-
- void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t level);
- void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);
-
- void _write_doc(size_t id);
- void _write_scalar(csubstr s, bool was_quoted);
- void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);
- void _write_scalar_literal(csubstr s, size_t level, bool as_key, bool explicit_indentation=false);
- void _write_scalar_folded(csubstr s, size_t level, bool as_key);
- void _write_scalar_squo(csubstr s, size_t level);
- void _write_scalar_dquo(csubstr s, size_t level);
- void _write_scalar_plain(csubstr s, size_t level);
-
- void _write_tag(csubstr tag)
- {
- if(!tag.begins_with('!'))
- this->Writer::_do_write('!');
- this->Writer::_do_write(tag);
- }
-
- enum : type_bits {
- _keysc = (KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
- _valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
- _keysc_json = (KEY) | ~(VAL),
- _valsc_json = ~(KEY) | (VAL),
- };
-
- C4_ALWAYS_INLINE void _writek(size_t id, size_t level) { _write(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~_valsc, level); }
- C4_ALWAYS_INLINE void _writev(size_t id, size_t level) { _write(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~_keysc, level); }
-
- C4_ALWAYS_INLINE void _writek_json(size_t id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
- C4_ALWAYS_INLINE void _writev_json(size_t id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
-
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** 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)
-{
- 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)
-{
- EmitterFile em(f);
- return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
-}
-
-
-/** emit YAML to the given file. A null file defaults to stdout.
- * Return the number of bytes written.
- * @overload */
-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 */
-inline size_t emit_json(Tree const& t, FILE *f=nullptr)
-{
- EmitterFile em(f);
- return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
-}
-
-
-/** emit YAML to the given file. A null file defaults to stdout.
- * Return the number of bytes written.
- * @overload */
-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 */
-inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
-{
- EmitterFile em(f);
- return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
-}
-
-
-//-----------------------------------------------------------------------------
-
-/** emit YAML to an STL-like ostream */
-template<class OStream>
-inline OStream& operator<< (OStream& s, Tree const& t)
-{
- EmitterOStream<OStream> em(s);
- em.emit_as(EMIT_YAML, t);
- return s;
-}
-
-/** emit YAML to an STL-like ostream
- * @overload */
-template<class OStream>
-inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
-{
- EmitterOStream<OStream> em(s);
- em.emit_as(EMIT_YAML, n);
- return s;
-}
-
-/** emit json to an STL-like stream */
-template<class OStream>
-inline OStream& operator<< (OStream& s, as_json const& j)
-{
- EmitterOStream<OStream> em(s);
- em.emit_as(EMIT_JSON, *j.tree, j.node, true);
- return s;
-}
-
-
-//-----------------------------------------------------------------------------
-
-
-/** 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.
- * @overload */
-inline substr emit_yaml(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
-{
- 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 */
-inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
-{
- EmitterBuf em(buf);
- return em.emit_as(EMIT_JSON, t, id, error_on_excess);
-}
-
-
-/** 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.
- * @overload */
-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 */
-inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
-{
- EmitterBuf em(buf);
- return em.emit_as(EMIT_JSON, t, error_on_excess);
-}
-
-
-/** 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.
- * @overload
- */
-inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
-{
- 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
- */
-inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
-{
- EmitterBuf em(buf);
- return em.emit_as(EMIT_JSON, r, error_on_excess);
-}
-
-
-//-----------------------------------------------------------------------------
-
-/** 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)
-{
- substr buf = to_substr(*cont);
- substr ret = emit_yaml(t, id, buf, /*error_on_excess*/false);
- if(ret.str == nullptr && ret.len > 0)
- {
- cont->resize(ret.len);
- buf = to_substr(*cont);
- ret = emit_yaml(t, id, buf, /*error_on_excess*/true);
- }
- 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
- * container, resizing it as needed to fit the emitted JSON. */
-template<class CharOwningContainer>
-substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
-{
- substr buf = to_substr(*cont);
- substr ret = emit_json(t, id, buf, /*error_on_excess*/false);
- if(ret.str == nullptr && ret.len > 0)
- {
- cont->resize(ret.len);
- buf = to_substr(*cont);
- ret = emit_json(t, id, buf, /*error_on_excess*/true);
- }
- return ret;
-}
-
-
-/** 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)
-{
- CharOwningContainer c;
- 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
- * container, resizing it as needed to fit the emitted JSON. */
-template<class CharOwningContainer>
-CharOwningContainer emitrs_json(Tree const& t, size_t id)
-{
- CharOwningContainer c;
- emitrs_json(t, id, &c);
- return c;
-}
-
-
-/** 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)
-{
- if(t.empty())
- 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
- * container, resizing it as needed to fit the emitted JSON. */
-template<class CharOwningContainer>
-substr emitrs_json(Tree const& t, CharOwningContainer * cont)
-{
- if(t.empty())
- return {};
- return emitrs_json(t, t.root_id(), cont);
-}
-
-
-/** 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)
-{
- CharOwningContainer c;
- if(t.empty())
- return c;
- 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,
- * resizing it as needed to fit the emitted JSON. */
-template<class CharOwningContainer>
-CharOwningContainer emitrs_json(Tree const& t)
-{
- CharOwningContainer c;
- if(t.empty())
- return c;
- emitrs_json(t, t.root_id(), &c);
- return c;
-}
-
-
-/** 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)
-{
- _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
- 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,
- * resizing it as needed to fit the emitted JSON. */
-template<class CharOwningContainer>
-substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)
-{
- _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
- return emitrs_json(*n.tree(), n.id(), cont);
-}
-
-
-/** 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)
-{
- _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
- CharOwningContainer c;
- 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,
- * resizing it as needed to fit the emitted JSON. */
-template<class CharOwningContainer>
-CharOwningContainer emitrs_json(ConstNodeRef const& n)
-{
- _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
- CharOwningContainer c;
- emitrs_json(*n.tree(), n.id(), &c);
- return c;
-}
-
-} // namespace yml
-} // namespace c4
-
-#undef RYML_DEPRECATE_EMIT
-#undef RYML_DEPRECATE_EMITRS
-
-#include "c4/yml/emit.def.hpp"
-
-#endif /* _C4_YML_EMIT_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/export.hpp b/thirdparty/ryml/src/c4/yml/export.hpp
deleted file mode 100644
index 6b77f3f8d..000000000
--- a/thirdparty/ryml/src/c4/yml/export.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef C4_YML_EXPORT_HPP_
-#define C4_YML_EXPORT_HPP_
-
-#ifdef _WIN32
- #ifdef RYML_SHARED
- #ifdef RYML_EXPORTS
- #define RYML_EXPORT __declspec(dllexport)
- #else
- #define RYML_EXPORT __declspec(dllimport)
- #endif
- #else
- #define RYML_EXPORT
- #endif
-#else
- #define RYML_EXPORT
-#endif
-
-#endif /* C4_YML_EXPORT_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/node.cpp b/thirdparty/ryml/src/c4/yml/node.cpp
deleted file mode 100644
index 50c7a0b60..000000000
--- a/thirdparty/ryml/src/c4/yml/node.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "c4/yml/node.hpp"
-
-namespace c4 {
-namespace yml {
-
-
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-size_t NodeRef::set_key_serialized(c4::fmt::const_base64_wrapper w)
-{
- _apply_seed();
- csubstr encoded = this->to_arena(w);
- this->set_key(encoded);
- return encoded.len;
-}
-
-size_t NodeRef::set_val_serialized(c4::fmt::const_base64_wrapper w)
-{
- _apply_seed();
- csubstr encoded = this->to_arena(w);
- this->set_val(encoded);
- return encoded.len;
-}
-
-} // namespace yml
-} // namespace c4
diff --git a/thirdparty/ryml/src/c4/yml/node.hpp b/thirdparty/ryml/src/c4/yml/node.hpp
deleted file mode 100644
index 42ed50442..000000000
--- a/thirdparty/ryml/src/c4/yml/node.hpp
+++ /dev/null
@@ -1,1276 +0,0 @@
-#ifndef _C4_YML_NODE_HPP_
-#define _C4_YML_NODE_HPP_
-
-/** @file node.hpp
- * @see NodeRef */
-
-#include <cstddef>
-
-#include "c4/yml/tree.hpp"
-#include "c4/base64.hpp"
-
-#ifdef __GNUC__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wtype-limits"
-#endif
-
-#if defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
-# pragma warning(disable: 4296/*expression is always 'boolean_value'*/)
-#endif
-
-namespace c4 {
-namespace yml {
-
-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; };
-
-template<class K> C4_ALWAYS_INLINE Key<K> key(K & k) { return Key<K>{k}; }
-C4_ALWAYS_INLINE Key<fmt::const_base64_wrapper> key(fmt::const_base64_wrapper w) { return {w}; }
-C4_ALWAYS_INLINE Key<fmt::base64_wrapper> key(fmt::base64_wrapper w) { return {w}; }
-
-template<class T> void write(NodeRef *n, T const& v);
-
-template<class T>
-typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type
-read(NodeRef const& n, T *v);
-
-template<class T>
-typename std::enable_if< std::is_floating_point<T>::value, bool>::type
-read(NodeRef const& n, T *v);
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-// forward decls
-class NodeRef;
-class ConstNodeRef;
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-namespace detail {
-
-template<class NodeRefType>
-struct child_iterator
-{
- using value_type = NodeRefType;
- using tree_type = typename NodeRefType::tree_type;
-
- tree_type * C4_RESTRICT m_tree;
- size_t m_child_id;
-
- child_iterator(tree_type * t, size_t id) : m_tree(t), m_child_id(id) {}
-
- child_iterator& operator++ () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->next_sibling(m_child_id); return *this; }
- child_iterator& operator-- () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->prev_sibling(m_child_id); return *this; }
-
- NodeRefType operator* () const { return NodeRefType(m_tree, m_child_id); }
- NodeRefType operator-> () const { return NodeRefType(m_tree, m_child_id); }
-
- bool operator!= (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id != that.m_child_id; }
- bool operator== (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id == that.m_child_id; }
-};
-
-template<class NodeRefType>
-struct children_view_
-{
- using n_iterator = child_iterator<NodeRefType>;
-
- n_iterator b, e;
-
- inline children_view_(n_iterator const& C4_RESTRICT b_,
- n_iterator const& C4_RESTRICT e_) : b(b_), e(e_) {}
-
- inline n_iterator begin() const { return b; }
- inline n_iterator end () const { return e; }
-};
-
-template<class NodeRefType, class Visitor>
-bool _visit(NodeRefType &node, Visitor fn, size_t indentation_level, bool skip_root=false)
-{
- size_t increment = 0;
- if( ! (node.is_root() && skip_root))
- {
- if(fn(node, indentation_level))
- return true;
- ++increment;
- }
- if(node.has_children())
- {
- for(auto ch : node.children())
- {
- if(_visit(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
- {
- return true;
- }
- }
- }
- return false;
-}
-
-template<class NodeRefType, class Visitor>
-bool _visit_stacked(NodeRefType &node, Visitor fn, size_t indentation_level, bool skip_root=false)
-{
- size_t increment = 0;
- if( ! (node.is_root() && skip_root))
- {
- if(fn(node, indentation_level))
- {
- return true;
- }
- ++increment;
- }
- if(node.has_children())
- {
- fn.push(node, indentation_level);
- for(auto ch : node.children())
- {
- if(_visit_stacked(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
- {
- fn.pop(node, indentation_level);
- return true;
- }
- }
- fn.pop(node, indentation_level);
- }
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-
-/** a CRTP base for read-only node methods */
-template<class Impl, class ConstImpl>
-struct RoNodeMethods
-{
- C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wcast-align")
- // 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
- #define tree__ ((Impl const* C4_RESTRICT)this)->m_tree
- #define id__ ((Impl const* C4_RESTRICT)this)->m_id
- // require valid
- #define _C4RV() \
- RYML_ASSERT(tree_ != nullptr); \
- _RYML_CB_ASSERT(tree_->m_callbacks, id_ != NONE)
- #define _C4_IF_MUTABLE(ty) typename std::enable_if<!std::is_same<U, ConstImpl>::value, ty>::type
-
-public:
-
- /** @name node property getters */
- /** @{ */
-
- /** returns the data or null when the id is NONE */
- C4_ALWAYS_INLINE C4_PURE NodeData const* get() const noexcept { RYML_ASSERT(tree_ != nullptr); return tree_->get(id_); }
- /** returns the data or null when the id is NONE */
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto get() noexcept -> _C4_IF_MUTABLE(NodeData*) { RYML_ASSERT(tree_ != nullptr); return tree__->get(id__); }
-
- C4_ALWAYS_INLINE C4_PURE NodeType type() const noexcept { _C4RV(); return tree_->type(id_); }
- C4_ALWAYS_INLINE C4_PURE const char* type_str() const noexcept { return tree_->type_str(id_); }
-
- C4_ALWAYS_INLINE C4_PURE csubstr key() const noexcept { _C4RV(); return tree_->key(id_); }
- C4_ALWAYS_INLINE C4_PURE csubstr key_tag() const noexcept { _C4RV(); return tree_->key_tag(id_); }
- C4_ALWAYS_INLINE C4_PURE csubstr key_ref() const noexcept { _C4RV(); return tree_->key_ref(id_); }
- C4_ALWAYS_INLINE C4_PURE csubstr key_anchor() const noexcept { _C4RV(); return tree_->key_anchor(id_); }
-
- C4_ALWAYS_INLINE C4_PURE csubstr val() const noexcept { _C4RV(); return tree_->val(id_); }
- C4_ALWAYS_INLINE C4_PURE csubstr val_tag() const noexcept { _C4RV(); return tree_->val_tag(id_); }
- C4_ALWAYS_INLINE C4_PURE csubstr val_ref() const noexcept { _C4RV(); return tree_->val_ref(id_); }
- C4_ALWAYS_INLINE C4_PURE csubstr val_anchor() const noexcept { _C4RV(); return tree_->val_anchor(id_); }
-
- C4_ALWAYS_INLINE C4_PURE NodeScalar const& keysc() const noexcept { _C4RV(); return tree_->keysc(id_); }
- C4_ALWAYS_INLINE C4_PURE NodeScalar const& valsc() const noexcept { _C4RV(); return tree_->valsc(id_); }
-
- C4_ALWAYS_INLINE C4_PURE bool key_is_null() const noexcept { _C4RV(); return tree_->key_is_null(id_); }
- C4_ALWAYS_INLINE C4_PURE bool val_is_null() const noexcept { _C4RV(); return tree_->val_is_null(id_); }
-
- /** @} */
-
-public:
-
- /** @name node property predicates */
- /** @{ */
-
- C4_ALWAYS_INLINE C4_PURE bool empty() const noexcept { _C4RV(); return tree_->empty(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_stream() const noexcept { _C4RV(); return tree_->is_stream(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_doc() const noexcept { _C4RV(); return tree_->is_doc(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_container() const noexcept { _C4RV(); return tree_->is_container(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_map() const noexcept { _C4RV(); return tree_->is_map(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_seq() const noexcept { _C4RV(); return tree_->is_seq(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_val() const noexcept { _C4RV(); return tree_->has_val(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_key() const noexcept { _C4RV(); return tree_->has_key(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_val() const noexcept { _C4RV(); return tree_->is_val(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_keyval() const noexcept { _C4RV(); return tree_->is_keyval(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_key_tag() const noexcept { _C4RV(); return tree_->has_key_tag(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_val_tag() const noexcept { _C4RV(); return tree_->has_val_tag(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_key_anchor() const noexcept { _C4RV(); return tree_->has_key_anchor(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_key_anchor() const noexcept { _C4RV(); return tree_->is_key_anchor(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_val_anchor() const noexcept { _C4RV(); return tree_->has_val_anchor(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_val_anchor() const noexcept { _C4RV(); return tree_->is_val_anchor(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_anchor() const noexcept { _C4RV(); return tree_->has_anchor(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_anchor() const noexcept { _C4RV(); return tree_->is_anchor(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_key_ref() const noexcept { _C4RV(); return tree_->is_key_ref(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_val_ref() const noexcept { _C4RV(); return tree_->is_val_ref(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_ref() const noexcept { _C4RV(); return tree_->is_ref(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_anchor_or_ref() const noexcept { _C4RV(); return tree_->is_anchor_or_ref(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_key_quoted() const noexcept { _C4RV(); return tree_->is_key_quoted(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_val_quoted() const noexcept { _C4RV(); return tree_->is_val_quoted(id_); }
- C4_ALWAYS_INLINE C4_PURE bool is_quoted() const noexcept { _C4RV(); return tree_->is_quoted(id_); }
- C4_ALWAYS_INLINE C4_PURE bool parent_is_seq() const noexcept { _C4RV(); return tree_->parent_is_seq(id_); }
- C4_ALWAYS_INLINE C4_PURE bool parent_is_map() const noexcept { _C4RV(); return tree_->parent_is_map(id_); }
-
- /** @} */
-
-public:
-
- /** @name hierarchy predicates */
- /** @{ */
-
- C4_ALWAYS_INLINE C4_PURE bool is_root() const noexcept { _C4RV(); return tree_->is_root(id_); }
- C4_ALWAYS_INLINE C4_PURE bool has_parent() const noexcept { _C4RV(); return tree_->has_parent(id_); }
-
- C4_ALWAYS_INLINE C4_PURE bool has_child(ConstImpl const& ch) const noexcept { _C4RV(); return tree_->has_child(id_, ch.m_id); }
- C4_ALWAYS_INLINE C4_PURE bool has_child(csubstr name) const noexcept { _C4RV(); return tree_->has_child(id_, name); }
- C4_ALWAYS_INLINE C4_PURE bool has_children() const noexcept { _C4RV(); return tree_->has_children(id_); }
-
- C4_ALWAYS_INLINE C4_PURE bool has_sibling(ConstImpl const& n) const noexcept { _C4RV(); return tree_->has_sibling(id_, n.m_id); }
- C4_ALWAYS_INLINE C4_PURE bool has_sibling(csubstr name) const noexcept { _C4RV(); return tree_->has_sibling(id_, name); }
- /** counts with this */
- C4_ALWAYS_INLINE C4_PURE bool has_siblings() const noexcept { _C4RV(); return tree_->has_siblings(id_); }
- /** does not count with this */
- C4_ALWAYS_INLINE C4_PURE bool has_other_siblings() const noexcept { _C4RV(); return tree_->has_other_siblings(id_); }
-
- /** @} */
-
-public:
-
- /** @name hierarchy getters */
- /** @{ */
-
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto doc(size_t num) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->doc(num)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl doc(size_t num) const noexcept { _C4RV(); return {tree_, tree_->doc(num)}; }
-
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto parent() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->parent(id__)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl parent() const noexcept { _C4RV(); return {tree_, tree_->parent(id_)}; }
-
-
- /** O(#num_children) */
- C4_ALWAYS_INLINE C4_PURE size_t child_pos(ConstImpl const& n) const noexcept { _C4RV(); return tree_->child_pos(id_, n.m_id); }
- C4_ALWAYS_INLINE C4_PURE size_t num_children() const noexcept { _C4RV(); return tree_->num_children(id_); }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto first_child() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->first_child(id__)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl first_child() const noexcept { _C4RV(); return {tree_, tree_->first_child(id_)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto last_child() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->last_child(id__)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl last_child () const noexcept { _C4RV(); return {tree_, tree_->last_child (id_)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto child(size_t pos) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->child(id__, pos)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl child(size_t pos) const noexcept { _C4RV(); return {tree_, tree_->child(id_, pos)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto find_child(csubstr name) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->find_child(id__, name)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl find_child(csubstr name) const noexcept { _C4RV(); return {tree_, tree_->find_child(id_, name)}; }
-
-
- /** O(#num_siblings) */
- C4_ALWAYS_INLINE C4_PURE size_t num_siblings() const noexcept { _C4RV(); return tree_->num_siblings(id_); }
- C4_ALWAYS_INLINE C4_PURE size_t num_other_siblings() const noexcept { _C4RV(); return tree_->num_other_siblings(id_); }
- C4_ALWAYS_INLINE C4_PURE size_t sibling_pos(ConstImpl const& n) const noexcept { _C4RV(); return tree_->child_pos(tree_->parent(id_), n.m_id); }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto prev_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->prev_sibling(id__)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl prev_sibling() const noexcept { _C4RV(); return {tree_, tree_->prev_sibling(id_)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto next_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->next_sibling(id__)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl next_sibling() const noexcept { _C4RV(); return {tree_, tree_->next_sibling(id_)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto first_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->first_sibling(id__)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl first_sibling() const noexcept { _C4RV(); return {tree_, tree_->first_sibling(id_)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto last_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->last_sibling(id__)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl last_sibling () const noexcept { _C4RV(); return {tree_, tree_->last_sibling(id_)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto sibling(size_t pos) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->sibling(id__, pos)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl sibling(size_t pos) const noexcept { _C4RV(); return {tree_, tree_->sibling(id_, pos)}; }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto find_sibling(csubstr name) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->find_sibling(id__, name)}; }
- C4_ALWAYS_INLINE C4_PURE ConstImpl find_sibling(csubstr name) const noexcept { _C4RV(); return {tree_, tree_->find_sibling(id_, name)}; }
-
-
- /** O(num_children) */
- C4_ALWAYS_INLINE C4_PURE ConstImpl operator[] (csubstr k) const noexcept
- {
- _C4RV();
- size_t ch = tree_->find_child(id_, k);
- _RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE);
- return {tree_, ch};
- }
- /** Find child by key. O(num_children). returns a seed node if no such child is found. */
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto operator[] (csubstr k) noexcept -> _C4_IF_MUTABLE(Impl)
- {
- _C4RV();
- size_t ch = tree__->find_child(id__, k);
- return ch != NONE ? Impl(tree__, ch) : NodeRef(tree__, id__, k);
- }
-
- /** O(num_children) */
- C4_ALWAYS_INLINE C4_PURE ConstImpl operator[] (size_t pos) const noexcept
- {
- _C4RV();
- size_t ch = tree_->child(id_, pos);
- _RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE);
- return {tree_, ch};
- }
-
- /** Find child by position. O(pos). returns a seed node if no such child is found. */
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto operator[] (size_t pos) noexcept -> _C4_IF_MUTABLE(Impl)
- {
- _C4RV();
- size_t ch = tree__->child(id__, pos);
- return ch != NONE ? Impl(tree__, ch) : NodeRef(tree__, id__, pos);
- }
-
- /** @} */
-
-public:
-
- /** deserialization */
- /** @{ */
-
- template<class T>
- ConstImpl const& operator>> (T &v) const
- {
- _C4RV();
- if( ! read((ConstImpl const&)*this, &v))
- _RYML_CB_ERR(tree_->m_callbacks, "could not deserialize value");
- return *((ConstImpl const*)this);
- }
-
- /** deserialize the node's key to the given variable */
- template<class T>
- ConstImpl const& operator>> (Key<T> v) const
- {
- _C4RV();
- if( ! from_chars(key(), &v.k))
- _RYML_CB_ERR(tree_->m_callbacks, "could not deserialize key");
- return *((ConstImpl const*)this);
- }
-
- /** deserialize the node's key as base64 */
- ConstImpl const& operator>> (Key<fmt::base64_wrapper> w) const
- {
- deserialize_key(w.wrapper);
- return *((ConstImpl const*)this);
- }
-
- /** deserialize the node's val as base64 */
- ConstImpl const& operator>> (fmt::base64_wrapper w) const
- {
- deserialize_val(w);
- return *((ConstImpl const*)this);
- }
-
- /** decode the base64-encoded key and assign the
- * decoded blob to the given buffer/
- * @return the size of base64-decoded blob */
- size_t deserialize_key(fmt::base64_wrapper v) const
- {
- _C4RV();
- return from_chars(key(), &v);
- }
- /** decode the base64-encoded key and assign the
- * decoded blob to the given buffer/
- * @return the size of base64-decoded blob */
- size_t deserialize_val(fmt::base64_wrapper v) const
- {
- _C4RV();
- return from_chars(val(), &v);
- };
-
- template<class T>
- bool get_if(csubstr name, T *var) const
- {
- auto ch = find_child(name);
- if(!ch.valid())
- return false;
- ch >> *var;
- return true;
- }
-
- template<class T>
- bool get_if(csubstr name, T *var, T const& fallback) const
- {
- auto ch = find_child(name);
- if(ch.valid())
- {
- ch >> *var;
- return true;
- }
- else
- {
- *var = fallback;
- return false;
- }
- }
-
- /** @} */
-
-public:
-
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Wnull-dereference"
- #elif defined(__GNUC__)
- # pragma GCC diagnostic push
- # if __GNUC__ >= 6
- # pragma GCC diagnostic ignored "-Wnull-dereference"
- # endif
- #endif
-
- /** @name iteration */
- /** @{ */
-
- using iterator = detail::child_iterator<Impl>;
- using const_iterator = detail::child_iterator<ConstImpl>;
- using children_view = detail::children_view_<Impl>;
- using const_children_view = detail::children_view_<ConstImpl>;
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto begin() noexcept -> _C4_IF_MUTABLE(iterator) { _C4RV(); return iterator(tree__, tree__->first_child(id__)); }
- C4_ALWAYS_INLINE C4_PURE const_iterator begin() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }
- C4_ALWAYS_INLINE C4_PURE const_iterator cbegin() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }
-
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto end() noexcept -> _C4_IF_MUTABLE(iterator) { _C4RV(); return iterator(tree__, NONE); }
- C4_ALWAYS_INLINE C4_PURE const_iterator end() const noexcept { _C4RV(); return const_iterator(tree_, NONE); }
- C4_ALWAYS_INLINE C4_PURE const_iterator cend() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }
-
- /** get an iterable view over children */
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto children() noexcept -> _C4_IF_MUTABLE(children_view) { _C4RV(); return children_view(begin(), end()); }
- /** get an iterable view over children */
- C4_ALWAYS_INLINE C4_PURE const_children_view children() const noexcept { _C4RV(); return const_children_view(begin(), end()); }
- /** get an iterable view over children */
- C4_ALWAYS_INLINE C4_PURE const_children_view cchildren() const noexcept { _C4RV(); return const_children_view(begin(), end()); }
-
- /** get an iterable view over all siblings (including the calling node) */
- template<class U=Impl>
- C4_ALWAYS_INLINE C4_PURE auto siblings() noexcept -> _C4_IF_MUTABLE(children_view)
- {
- _C4RV();
- NodeData const *nd = tree__->get(id__);
- return (nd->m_parent != NONE) ? // does it have a parent?
- children_view(iterator(tree__, tree_->get(nd->m_parent)->m_first_child), iterator(tree__, NONE))
- :
- children_view(end(), end());
- }
- /** get an iterable view over all siblings (including the calling node) */
- C4_ALWAYS_INLINE C4_PURE const_children_view siblings() const noexcept
- {
- _C4RV();
- NodeData const *nd = tree_->get(id_);
- return (nd->m_parent != NONE) ? // does it have a parent?
- const_children_view(const_iterator(tree_, tree_->get(nd->m_parent)->m_first_child), const_iterator(tree_, NONE))
- :
- const_children_view(end(), end());
- }
- /** get an iterable view over all siblings (including the calling node) */
- C4_ALWAYS_INLINE C4_PURE const_children_view csiblings() const noexcept { return siblings(); }
-
- /** visit every child node calling fn(node) */
- template<class Visitor>
- C4_ALWAYS_INLINE C4_PURE bool visit(Visitor fn, size_t indentation_level=0, bool skip_root=true) const noexcept
- {
- return detail::_visit(*(ConstImpl*)this, fn, indentation_level, skip_root);
- }
- /** visit every child node calling fn(node) */
- template<class Visitor, class U=Impl>
- auto visit(Visitor fn, size_t indentation_level=0, bool skip_root=true) noexcept
- -> _C4_IF_MUTABLE(bool)
- {
- return detail::_visit(*(Impl*)this, fn, indentation_level, skip_root);
- }
-
- /** visit every child node calling fn(node, level) */
- template<class Visitor>
- C4_ALWAYS_INLINE C4_PURE bool visit_stacked(Visitor fn, size_t indentation_level=0, bool skip_root=true) const noexcept
- {
- return detail::_visit_stacked(*(ConstImpl*)this, fn, indentation_level, skip_root);
- }
- /** visit every child node calling fn(node, level) */
- template<class Visitor, class U=Impl>
- auto visit_stacked(Visitor fn, size_t indentation_level=0, bool skip_root=true) noexcept
- -> _C4_IF_MUTABLE(bool)
- {
- return detail::_visit_stacked(*(Impl*)this, fn, indentation_level, skip_root);
- }
-
- /** @} */
-
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #elif defined(__GNUC__)
- # pragma GCC diagnostic pop
- #endif
-
- #undef _C4_IF_MUTABLE
- #undef _C4RV
- #undef tree_
- #undef tree__
- #undef id_
- #undef id__
-
- C4_SUPPRESS_WARNING_GCC_CLANG_POP
-};
-
-} // namespace detail
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-class RYML_EXPORT ConstNodeRef : public detail::RoNodeMethods<ConstNodeRef, ConstNodeRef>
-{
-public:
-
- using tree_type = Tree const;
-
-public:
-
- Tree const* C4_RESTRICT m_tree;
- size_t m_id;
-
- friend NodeRef;
- friend struct detail::RoNodeMethods<ConstNodeRef, ConstNodeRef>;
-
-public:
-
- /** @name construction */
- /** @{ */
-
- ConstNodeRef() : m_tree(nullptr), m_id(NONE) {}
- ConstNodeRef(Tree const &t) : m_tree(&t), m_id(t .root_id()) {}
- ConstNodeRef(Tree const *t) : m_tree(t ), m_id(t->root_id()) {}
- ConstNodeRef(Tree const *t, size_t id) : m_tree(t), m_id(id) {}
- ConstNodeRef(std::nullptr_t) : m_tree(nullptr), m_id(NONE) {}
-
- ConstNodeRef(ConstNodeRef const&) = default;
- ConstNodeRef(ConstNodeRef &&) = default;
-
- ConstNodeRef(NodeRef const&);
- ConstNodeRef(NodeRef &&);
-
- /** @} */
-
-public:
-
- /** @name assignment */
- /** @{ */
-
- ConstNodeRef& operator= (std::nullptr_t) { m_tree = nullptr; m_id = NONE; return *this; }
-
- ConstNodeRef& operator= (ConstNodeRef const&) = default;
- ConstNodeRef& operator= (ConstNodeRef &&) = default;
-
- ConstNodeRef& operator= (NodeRef const&);
- ConstNodeRef& operator= (NodeRef &&);
-
-
- /** @} */
-
-public:
-
- /** @name state queries */
- /** @{ */
-
- C4_ALWAYS_INLINE C4_PURE bool valid() const noexcept { return m_tree != nullptr && m_id != NONE; }
-
- /** @} */
-
-public:
-
- /** @name member getters */
- /** @{ */
-
- C4_ALWAYS_INLINE C4_PURE Tree const* tree() const noexcept { return m_tree; }
- C4_ALWAYS_INLINE C4_PURE size_t id() const noexcept { return m_id; }
-
- /** @} */
-
-public:
-
- /** @name comparisons */
- /** @{ */
-
- C4_ALWAYS_INLINE C4_PURE bool operator== (ConstNodeRef const& that) const noexcept { RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }
- C4_ALWAYS_INLINE C4_PURE bool operator!= (ConstNodeRef const& that) const noexcept { RYML_ASSERT(that.m_tree == m_tree); return ! this->operator==(that); }
-
- C4_ALWAYS_INLINE C4_PURE bool operator== (std::nullptr_t) const noexcept { return m_tree == nullptr || m_id == NONE; }
- C4_ALWAYS_INLINE C4_PURE bool operator!= (std::nullptr_t) const noexcept { return ! this->operator== (nullptr); }
-
- C4_ALWAYS_INLINE C4_PURE bool operator== (csubstr val) const noexcept { RYML_ASSERT(has_val()); return m_tree->val(m_id) == val; }
- C4_ALWAYS_INLINE C4_PURE bool operator!= (csubstr val) const noexcept { RYML_ASSERT(has_val()); return m_tree->val(m_id) != val; }
-
- /** @} */
-
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** a reference to a node in an existing yaml tree, offering a more
- * convenient API than the index-based API used in the tree. */
-class RYML_EXPORT NodeRef : public detail::RoNodeMethods<NodeRef, ConstNodeRef>
-{
-public:
-
- using tree_type = Tree;
- using base_type = detail::RoNodeMethods<NodeRef, ConstNodeRef>;
-
-private:
-
- Tree *C4_RESTRICT m_tree;
- size_t m_id;
-
- /** This member is used to enable lazy operator[] writing. When a child
- * with a key or index is not found, m_id is set to the id of the parent
- * and the asked-for key or index are stored in this member until a write
- * does happen. Then it is given as key or index for creating the child.
- * When a key is used, the csubstr stores it (so the csubstr's string is
- * non-null and the csubstr's size is different from NONE). When an index is
- * used instead, the csubstr's string is set to null, and only the csubstr's
- * size is set to a value different from NONE. Otherwise, when operator[]
- * does find the child then this member is empty: the string is null and
- * the size is NONE. */
- csubstr m_seed;
-
- friend ConstNodeRef;
- friend struct detail::RoNodeMethods<NodeRef, ConstNodeRef>;
-
- // require valid: a helper macro, undefined at the end
- #define _C4RV() \
- RYML_ASSERT(m_tree != nullptr); \
- _RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE && !is_seed())
-
-public:
-
- /** @name construction */
- /** @{ */
-
- NodeRef() : m_tree(nullptr), m_id(NONE), m_seed() { _clear_seed(); }
- NodeRef(Tree &t) : m_tree(&t), m_id(t .root_id()), m_seed() { _clear_seed(); }
- NodeRef(Tree *t) : m_tree(t ), m_id(t->root_id()), m_seed() { _clear_seed(); }
- NodeRef(Tree *t, size_t id) : m_tree(t), m_id(id), m_seed() { _clear_seed(); }
- NodeRef(Tree *t, size_t id, size_t seed_pos) : m_tree(t), m_id(id), m_seed() { m_seed.str = nullptr; m_seed.len = seed_pos; }
- 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() {}
-
- /** @} */
-
-public:
-
- /** @name assignment */
- /** @{ */
-
- NodeRef(NodeRef const&) = default;
- NodeRef(NodeRef &&) = default;
-
- NodeRef& operator= (NodeRef const&) = default;
- NodeRef& operator= (NodeRef &&) = default;
-
- /** @} */
-
-public:
-
- /** @name state queries */
- /** @{ */
-
- inline bool valid() const { return m_tree != nullptr && m_id != NONE; }
- inline bool is_seed() const { return m_seed.str != nullptr || m_seed.len != NONE; }
-
- inline void _clear_seed() { /*do this manually or an assert is triggered*/ m_seed.str = nullptr; m_seed.len = NONE; }
-
- /** @} */
-
-public:
-
- /** @name comparisons */
- /** @{ */
-
- inline bool operator== (NodeRef const& that) const { _C4RV(); RYML_ASSERT(that.valid() && !that.is_seed()); RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }
- inline bool operator!= (NodeRef const& that) const { return ! this->operator==(that); }
-
- inline bool operator== (ConstNodeRef const& that) const { _C4RV(); RYML_ASSERT(that.valid()); RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }
- inline bool operator!= (ConstNodeRef const& that) const { return ! this->operator==(that); }
-
- inline bool operator== (std::nullptr_t) const { return m_tree == nullptr || m_id == NONE || is_seed(); }
- inline bool operator!= (std::nullptr_t) const { return m_tree != nullptr && m_id != NONE && !is_seed(); }
-
- inline bool operator== (csubstr val) const { _C4RV(); RYML_ASSERT(has_val()); return m_tree->val(m_id) == val; }
- inline bool operator!= (csubstr val) const { _C4RV(); RYML_ASSERT(has_val()); return m_tree->val(m_id) != val; }
-
- //inline operator bool () const { return m_tree == nullptr || m_id == NONE || is_seed(); }
-
- /** @} */
-
-public:
-
- /** @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; }
-
- C4_ALWAYS_INLINE C4_PURE size_t id() const noexcept { return m_id; }
-
- /** @} */
-
-public:
-
- /** @name node modifiers */
- /** @{ */
-
- void change_type(NodeType t) { _C4RV(); m_tree->change_type(m_id, t); }
-
- void set_type(NodeType t) { _C4RV(); m_tree->_set_flags(m_id, t); }
- void set_key(csubstr key) { _C4RV(); m_tree->_set_key(m_id, key); }
- void set_val(csubstr val) { _C4RV(); m_tree->_set_val(m_id, val); }
- void set_key_tag(csubstr key_tag) { _C4RV(); m_tree->set_key_tag(m_id, key_tag); }
- void set_val_tag(csubstr val_tag) { _C4RV(); m_tree->set_val_tag(m_id, val_tag); }
- void set_key_anchor(csubstr key_anchor) { _C4RV(); m_tree->set_key_anchor(m_id, key_anchor); }
- void set_val_anchor(csubstr val_anchor) { _C4RV(); m_tree->set_val_anchor(m_id, val_anchor); }
- void set_key_ref(csubstr key_ref) { _C4RV(); m_tree->set_key_ref(m_id, key_ref); }
- void set_val_ref(csubstr val_ref) { _C4RV(); m_tree->set_val_ref(m_id, val_ref); }
-
- template<class T>
- size_t set_key_serialized(T const& C4_RESTRICT k)
- {
- _C4RV();
- csubstr s = m_tree->to_arena(k);
- m_tree->_set_key(m_id, s);
- return s.len;
- }
- template<class T>
- size_t set_val_serialized(T const& C4_RESTRICT v)
- {
- _C4RV();
- csubstr s = m_tree->to_arena(v);
- m_tree->_set_val(m_id, s);
- return s.len;
- }
- size_t set_val_serialized(std::nullptr_t)
- {
- _C4RV();
- m_tree->_set_val(m_id, csubstr{});
- return 0;
- }
-
- /** encode a blob as base64, then assign the result to the node's key
- * @return the size of base64-encoded blob */
- size_t set_key_serialized(fmt::const_base64_wrapper w);
- /** encode a blob as base64, then assign the result to the node's val
- * @return the size of base64-encoded blob */
- size_t set_val_serialized(fmt::const_base64_wrapper w);
-
-public:
-
- inline void clear()
- {
- if(is_seed())
- return;
- m_tree->remove_children(m_id);
- m_tree->_clear(m_id);
- }
-
- inline void clear_key()
- {
- if(is_seed())
- return;
- m_tree->_clear_key(m_id);
- }
-
- inline void clear_val()
- {
- if(is_seed())
- return;
- m_tree->_clear_val(m_id);
- }
-
- inline void clear_children()
- {
- if(is_seed())
- return;
- m_tree->remove_children(m_id);
- }
-
- void create() { _apply_seed(); }
-
- inline void operator= (NodeType_e t)
- {
- _apply_seed();
- m_tree->_add_flags(m_id, t);
- }
-
- inline void operator|= (NodeType_e t)
- {
- _apply_seed();
- m_tree->_add_flags(m_id, t);
- }
-
- inline void operator= (NodeInit const& v)
- {
- _apply_seed();
- _apply(v);
- }
-
- inline void operator= (NodeScalar const& v)
- {
- _apply_seed();
- _apply(v);
- }
-
- inline void operator= (std::nullptr_t)
- {
- _apply_seed();
- _apply(csubstr{});
- }
-
- inline void operator= (csubstr v)
- {
- _apply_seed();
- _apply(v);
- }
-
- template<size_t N>
- inline void operator= (const char (&v)[N])
- {
- _apply_seed();
- csubstr sv;
- sv.assign<N>(v);
- _apply(sv);
- }
-
- /** @} */
-
-public:
-
- /** @name serialization */
- /** @{ */
-
- /** serialize a variable to the arena */
- template<class T>
- inline csubstr to_arena(T const& C4_RESTRICT s)
- {
- _C4RV();
- return m_tree->to_arena(s);
- }
-
- /** serialize a variable, then assign the result to the node's val */
- inline NodeRef& operator<< (csubstr s)
- {
- // this overload is needed to prevent ambiguity (there's also
- // operator<< for writing a substr to a stream)
- _apply_seed();
- write(this, s);
- RYML_ASSERT(val() == s);
- return *this;
- }
-
- template<class T>
- inline NodeRef& operator<< (T const& C4_RESTRICT v)
- {
- _apply_seed();
- write(this, v);
- return *this;
- }
-
- /** serialize a variable, then assign the result to the node's key */
- template<class T>
- inline NodeRef& operator<< (Key<const T> const& C4_RESTRICT v)
- {
- _apply_seed();
- set_key_serialized(v.k);
- return *this;
- }
-
- /** serialize a variable, then assign the result to the node's key */
- template<class T>
- inline NodeRef& operator<< (Key<T> const& C4_RESTRICT v)
- {
- _apply_seed();
- set_key_serialized(v.k);
- return *this;
- }
-
- NodeRef& operator<< (Key<fmt::const_base64_wrapper> w)
- {
- set_key_serialized(w.wrapper);
- return *this;
- }
-
- NodeRef& operator<< (fmt::const_base64_wrapper w)
- {
- set_val_serialized(w);
- return *this;
- }
-
- /** @} */
-
-private:
-
- void _apply_seed()
- {
- if(m_seed.str) // we have a seed key: use it to create the new child
- {
- //RYML_ASSERT(i.key.scalar.empty() || m_key == i.key.scalar || m_key.empty());
- m_id = m_tree->append_child(m_id);
- m_tree->_set_key(m_id, m_seed);
- m_seed.str = nullptr;
- m_seed.len = NONE;
- }
- else if(m_seed.len != NONE) // we have a seed index: create a child at that position
- {
- RYML_ASSERT(m_tree->num_children(m_id) == m_seed.len);
- m_id = m_tree->append_child(m_id);
- m_seed.str = nullptr;
- m_seed.len = NONE;
- }
- else
- {
- RYML_ASSERT(valid());
- }
- }
-
- inline void _apply(csubstr v)
- {
- m_tree->_set_val(m_id, v);
- }
-
- inline void _apply(NodeScalar const& v)
- {
- m_tree->_set_val(m_id, v);
- }
-
- inline void _apply(NodeInit const& i)
- {
- m_tree->_set(m_id, i);
- }
-
-public:
-
- /** @name modification of hierarchy */
- /** @{ */
-
- inline NodeRef insert_child(NodeRef after)
- {
- _C4RV();
- RYML_ASSERT(after.m_tree == m_tree);
- NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
- return r;
- }
-
- inline NodeRef insert_child(NodeInit const& i, NodeRef after)
- {
- _C4RV();
- RYML_ASSERT(after.m_tree == m_tree);
- NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
- r._apply(i);
- return r;
- }
-
- inline NodeRef prepend_child()
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
- return r;
- }
-
- inline NodeRef prepend_child(NodeInit const& i)
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
- r._apply(i);
- return r;
- }
-
- inline NodeRef append_child()
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->append_child(m_id));
- return r;
- }
-
- inline NodeRef append_child(NodeInit const& i)
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->append_child(m_id));
- r._apply(i);
- return r;
- }
-
-public:
-
- inline NodeRef insert_sibling(ConstNodeRef const& after)
- {
- _C4RV();
- RYML_ASSERT(after.m_tree == m_tree);
- NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
- return r;
- }
-
- inline NodeRef insert_sibling(NodeInit const& i, ConstNodeRef const& after)
- {
- _C4RV();
- RYML_ASSERT(after.m_tree == m_tree);
- NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
- r._apply(i);
- return r;
- }
-
- inline NodeRef prepend_sibling()
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
- return r;
- }
-
- inline NodeRef prepend_sibling(NodeInit const& i)
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
- r._apply(i);
- return r;
- }
-
- inline NodeRef append_sibling()
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->append_sibling(m_id));
- return r;
- }
-
- inline NodeRef append_sibling(NodeInit const& i)
- {
- _C4RV();
- NodeRef r(m_tree, m_tree->append_sibling(m_id));
- r._apply(i);
- return r;
- }
-
-public:
-
- inline void remove_child(NodeRef & child)
- {
- _C4RV();
- RYML_ASSERT(has_child(child));
- RYML_ASSERT(child.parent().id() == id());
- m_tree->remove(child.id());
- child.clear();
- }
-
- //! remove the nth child of this node
- inline void remove_child(size_t pos)
- {
- _C4RV();
- RYML_ASSERT(pos >= 0 && pos < num_children());
- size_t child = m_tree->child(m_id, pos);
- RYML_ASSERT(child != NONE);
- m_tree->remove(child);
- }
-
- //! remove a child by name
- inline void remove_child(csubstr key)
- {
- _C4RV();
- size_t child = m_tree->find_child(m_id, key);
- RYML_ASSERT(child != NONE);
- m_tree->remove(child);
- }
-
-public:
-
- /** change the node's position within its parent, placing it after
- * @p after. To move to the first position in the parent, simply
- * pass an empty or default-constructed reference like this:
- * `n.move({})`. */
- inline void move(ConstNodeRef const& after)
- {
- _C4RV();
- m_tree->move(m_id, after.m_id);
- }
-
- /** move the node to a different @p parent (which may belong to a
- * different tree), placing it after @p after. When the
- * destination parent is in a new tree, then this node's tree
- * pointer is reset to the tree of the parent node. */
- inline void move(NodeRef const& parent, ConstNodeRef const& after)
- {
- _C4RV();
- if(parent.m_tree == m_tree)
- {
- m_tree->move(m_id, parent.m_id, after.m_id);
- }
- else
- {
- parent.m_tree->move(m_tree, m_id, parent.m_id, after.m_id);
- m_tree = parent.m_tree;
- }
- }
-
- /** duplicate the current node somewhere within its parent, and
- * place it after the node @p after. To place into the first
- * position of the parent, simply pass an empty or
- * default-constructed reference like this: `n.move({})`. */
- inline NodeRef duplicate(ConstNodeRef const& after) const
- {
- _C4RV();
- RYML_ASSERT(m_tree == after.m_tree || after.m_id == NONE);
- size_t dup = m_tree->duplicate(m_id, m_tree->parent(m_id), after.m_id);
- NodeRef r(m_tree, dup);
- return r;
- }
-
- /** duplicate the current node somewhere into a different @p parent
- * (possibly from a different tree), and place it after the node
- * @p after. To place into the first position of the parent,
- * simply pass an empty or default-constructed reference like
- * this: `n.move({})`. */
- inline NodeRef duplicate(NodeRef const& parent, ConstNodeRef const& after) const
- {
- _C4RV();
- RYML_ASSERT(parent.m_tree == after.m_tree || after.m_id == NONE);
- if(parent.m_tree == m_tree)
- {
- size_t dup = m_tree->duplicate(m_id, parent.m_id, after.m_id);
- NodeRef r(m_tree, dup);
- return r;
- }
- else
- {
- size_t dup = parent.m_tree->duplicate(m_tree, m_id, parent.m_id, after.m_id);
- NodeRef r(parent.m_tree, dup);
- return r;
- }
- }
-
- inline void duplicate_children(NodeRef const& parent, ConstNodeRef const& after) const
- {
- _C4RV();
- RYML_ASSERT(parent.m_tree == after.m_tree);
- if(parent.m_tree == m_tree)
- {
- m_tree->duplicate_children(m_id, parent.m_id, after.m_id);
- }
- else
- {
- parent.m_tree->duplicate_children(m_tree, m_id, parent.m_id, after.m_id);
- }
- }
-
- /** @} */
-
-#undef _C4RV
-};
-
-
-//-----------------------------------------------------------------------------
-
-inline ConstNodeRef::ConstNodeRef(NodeRef const& that)
- : m_tree(that.m_tree)
- , m_id(!that.is_seed() ? that.id() : NONE)
-{
-}
-
-inline ConstNodeRef::ConstNodeRef(NodeRef && that)
- : m_tree(that.m_tree)
- , m_id(!that.is_seed() ? that.id() : NONE)
-{
-}
-
-
-inline ConstNodeRef& ConstNodeRef::operator= (NodeRef const& that)
-{
- m_tree = (that.m_tree);
- m_id = (!that.is_seed() ? that.id() : NONE);
- return *this;
-}
-
-inline ConstNodeRef& ConstNodeRef::operator= (NodeRef && that)
-{
- m_tree = (that.m_tree);
- m_id = (!that.is_seed() ? that.id() : NONE);
- return *this;
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<class T>
-inline void write(NodeRef *n, T const& v)
-{
- n->set_val_serialized(v);
-}
-
-template<class T>
-typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type
-inline read(NodeRef const& n, T *v)
-{
- return from_chars(n.val(), v);
-}
-template<class T>
-typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type
-inline read(ConstNodeRef const& n, T *v)
-{
- return from_chars(n.val(), v);
-}
-
-template<class T>
-typename std::enable_if<std::is_floating_point<T>::value, bool>::type
-inline read(NodeRef const& n, T *v)
-{
- return from_chars_float(n.val(), v);
-}
-template<class T>
-typename std::enable_if<std::is_floating_point<T>::value, bool>::type
-inline read(ConstNodeRef const& n, T *v)
-{
- return from_chars_float(n.val(), v);
-}
-
-
-} // namespace yml
-} // namespace c4
-
-
-#if defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-#ifdef __GNUC__
-# pragma GCC diagnostic pop
-#endif
-
-#endif /* _C4_YML_NODE_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/parse.cpp b/thirdparty/ryml/src/c4/yml/parse.cpp
deleted file mode 100644
index 7b038e672..000000000
--- a/thirdparty/ryml/src/c4/yml/parse.cpp
+++ /dev/null
@@ -1,5724 +0,0 @@
-#include "c4/yml/parse.hpp"
-#include "c4/error.hpp"
-#include "c4/utf.hpp"
-#include <c4/dump.hpp>
-
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "c4/yml/detail/parser_dbg.hpp"
-#ifdef RYML_DBG
-#include "c4/yml/detail/print.hpp"
-#endif
-
-#ifndef RYML_ERRMSG_SIZE
- #define RYML_ERRMSG_SIZE 1024
-#endif
-
-//#define RYML_WITH_TAB_TOKENS
-#ifdef RYML_WITH_TAB_TOKENS
-#define _RYML_WITH_TAB_TOKENS(...) __VA_ARGS__
-#define _RYML_WITH_OR_WITHOUT_TAB_TOKENS(with, without) with
-#else
-#define _RYML_WITH_TAB_TOKENS(...)
-#define _RYML_WITH_OR_WITHOUT_TAB_TOKENS(with, without) without
-#endif
-
-
-#if defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4296/*expression is always 'boolean_value'*/)
-#elif defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wtype-limits" // to remove a warning on an assertion that a size_t >= 0. Later on, this size_t will turn into a template argument, and then it can become < 0.
-# pragma clang diagnostic ignored "-Wformat-nonliteral"
-#elif defined(__GNUC__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wtype-limits" // to remove a warning on an assertion that a size_t >= 0. Later on, this size_t will turn into a template argument, and then it can become < 0.
-# pragma GCC diagnostic ignored "-Wformat-nonliteral"
-# if __GNUC__ >= 7
-# pragma GCC diagnostic ignored "-Wduplicated-branches"
-# endif
-#endif
-
-namespace c4 {
-namespace yml {
-
-namespace {
-
-template<class DumpFn, class ...Args>
-void _parse_dump(DumpFn dumpfn, c4::csubstr fmt, Args&& ...args)
-{
- char writebuf[256];
- auto results = c4::format_dump_resume(dumpfn, writebuf, fmt, std::forward<Args>(args)...);
- // resume writing if the results failed to fit the buffer
- if(C4_UNLIKELY(results.bufsize > sizeof(writebuf))) // bufsize will be that of the largest element serialized. Eg int(1), will require 1 byte.
- {
- results = format_dump_resume(dumpfn, results, writebuf, fmt, std::forward<Args>(args)...);
- if(C4_UNLIKELY(results.bufsize > sizeof(writebuf)))
- {
- results = format_dump_resume(dumpfn, results, writebuf, fmt, std::forward<Args>(args)...);
- }
- }
-}
-
-bool _is_scalar_next__runk(csubstr s)
-{
- return !(s.begins_with(": ") || s.begins_with_any("#,{}[]%&") || s.begins_with("? ") || s == "-" || s.begins_with("- ") || s.begins_with(":\"") || s.begins_with(":'"));
-}
-
-bool _is_scalar_next__rseq_rval(csubstr s)
-{
- return !(s.begins_with_any("[{!&") || s.begins_with("? ") || s.begins_with("- ") || s == "-");
-}
-
-bool _is_scalar_next__rmap(csubstr s)
-{
- return !(s.begins_with(": ") || s.begins_with_any("#,!&") || s.begins_with("? ") _RYML_WITH_TAB_TOKENS(|| s.begins_with(":\t")));
-}
-
-bool _is_scalar_next__rmap_val(csubstr s)
-{
- return !(s.begins_with("- ") || s.begins_with_any("{[") || s == "-");
-}
-
-bool _is_doc_sep(csubstr s)
-{
- constexpr const csubstr dashes = "---";
- constexpr const csubstr ellipsis = "...";
- constexpr const csubstr whitesp = " \t";
- if(s.begins_with(dashes))
- return s == dashes || s.sub(3).begins_with_any(whitesp);
- else if(s.begins_with(ellipsis))
- return s == ellipsis || s.sub(3).begins_with_any(whitesp);
- return false;
-}
-
-/** @p i is set to the first non whitespace character after the line
- * @return the number of empty lines after the initial position */
-size_t count_following_newlines(csubstr r, size_t *C4_RESTRICT i, size_t indentation)
-{
- RYML_ASSERT(r[*i] == '\n');
- size_t numnl_following = 0;
- ++(*i);
- for( ; *i < r.len; ++(*i))
- {
- if(r.str[*i] == '\n')
- {
- ++numnl_following;
- if(indentation) // skip the indentation after the newline
- {
- size_t stop = *i + indentation;
- for( ; *i < r.len; ++(*i))
- {
- if(r.str[*i] != ' ' && r.str[*i] != '\r')
- break;
- RYML_ASSERT(*i < stop);
- }
- C4_UNUSED(stop);
- }
- }
- else if(r.str[*i] == ' ' || r.str[*i] == '\t' || r.str[*i] == '\r') // skip leading whitespace
- ;
- else
- break;
- }
- return numnl_following;
-}
-
-} // anon namespace
-
-
-//-----------------------------------------------------------------------------
-
-Parser::~Parser()
-{
- _free();
- _clr();
-}
-
-Parser::Parser(Callbacks const& cb, ParserOptions opts)
- : m_options(opts)
- , m_file()
- , m_buf()
- , m_root_id(NONE)
- , m_tree()
- , m_stack(cb)
- , m_state()
- , m_key_tag_indentation(0)
- , m_key_tag2_indentation(0)
- , m_key_tag()
- , m_key_tag2()
- , m_val_tag_indentation(0)
- , m_val_tag()
- , m_key_anchor_was_before(false)
- , m_key_anchor_indentation(0)
- , m_key_anchor()
- , m_val_anchor_indentation(0)
- , m_val_anchor()
- , m_filter_arena()
- , m_newline_offsets()
- , m_newline_offsets_size(0)
- , m_newline_offsets_capacity(0)
- , m_newline_offsets_buf()
-{
- m_stack.push(State{});
- m_state = &m_stack.top();
-}
-
-Parser::Parser(Parser &&that)
- : m_options(that.m_options)
- , m_file(that.m_file)
- , m_buf(that.m_buf)
- , m_root_id(that.m_root_id)
- , m_tree(that.m_tree)
- , m_stack(std::move(that.m_stack))
- , m_state(&m_stack.top())
- , m_key_tag_indentation(that.m_key_tag_indentation)
- , m_key_tag2_indentation(that.m_key_tag2_indentation)
- , m_key_tag(that.m_key_tag)
- , m_key_tag2(that.m_key_tag2)
- , m_val_tag_indentation(that.m_val_tag_indentation)
- , m_val_tag(that.m_val_tag)
- , m_key_anchor_was_before(that.m_key_anchor_was_before)
- , m_key_anchor_indentation(that.m_key_anchor_indentation)
- , m_key_anchor(that.m_key_anchor)
- , m_val_anchor_indentation(that.m_val_anchor_indentation)
- , m_val_anchor(that.m_val_anchor)
- , m_filter_arena(that.m_filter_arena)
- , m_newline_offsets(that.m_newline_offsets)
- , m_newline_offsets_size(that.m_newline_offsets_size)
- , m_newline_offsets_capacity(that.m_newline_offsets_capacity)
- , m_newline_offsets_buf(that.m_newline_offsets_buf)
-{
- that._clr();
-}
-
-Parser::Parser(Parser const& that)
- : m_options(that.m_options)
- , m_file(that.m_file)
- , m_buf(that.m_buf)
- , m_root_id(that.m_root_id)
- , m_tree(that.m_tree)
- , m_stack(that.m_stack)
- , m_state(&m_stack.top())
- , m_key_tag_indentation(that.m_key_tag_indentation)
- , m_key_tag2_indentation(that.m_key_tag2_indentation)
- , m_key_tag(that.m_key_tag)
- , m_key_tag2(that.m_key_tag2)
- , m_val_tag_indentation(that.m_val_tag_indentation)
- , m_val_tag(that.m_val_tag)
- , m_key_anchor_was_before(that.m_key_anchor_was_before)
- , m_key_anchor_indentation(that.m_key_anchor_indentation)
- , m_key_anchor(that.m_key_anchor)
- , m_val_anchor_indentation(that.m_val_anchor_indentation)
- , m_val_anchor(that.m_val_anchor)
- , m_filter_arena()
- , m_newline_offsets()
- , m_newline_offsets_size()
- , m_newline_offsets_capacity()
- , m_newline_offsets_buf()
-{
- if(that.m_newline_offsets_capacity)
- {
- _resize_locations(that.m_newline_offsets_capacity);
- _RYML_CB_CHECK(m_stack.m_callbacks, m_newline_offsets_capacity == that.m_newline_offsets_capacity);
- memcpy(m_newline_offsets, that.m_newline_offsets, that.m_newline_offsets_size * sizeof(size_t));
- m_newline_offsets_size = that.m_newline_offsets_size;
- }
- if(that.m_filter_arena.len)
- {
- _resize_filter_arena(that.m_filter_arena.len);
- }
-}
-
-Parser& Parser::operator=(Parser &&that)
-{
- _free();
- m_options = (that.m_options);
- m_file = (that.m_file);
- m_buf = (that.m_buf);
- m_root_id = (that.m_root_id);
- m_tree = (that.m_tree);
- m_stack = std::move(that.m_stack);
- m_state = (&m_stack.top());
- m_key_tag_indentation = (that.m_key_tag_indentation);
- m_key_tag2_indentation = (that.m_key_tag2_indentation);
- m_key_tag = (that.m_key_tag);
- m_key_tag2 = (that.m_key_tag2);
- m_val_tag_indentation = (that.m_val_tag_indentation);
- m_val_tag = (that.m_val_tag);
- m_key_anchor_was_before = (that.m_key_anchor_was_before);
- m_key_anchor_indentation = (that.m_key_anchor_indentation);
- m_key_anchor = (that.m_key_anchor);
- m_val_anchor_indentation = (that.m_val_anchor_indentation);
- m_val_anchor = (that.m_val_anchor);
- m_filter_arena = that.m_filter_arena;
- m_newline_offsets = (that.m_newline_offsets);
- m_newline_offsets_size = (that.m_newline_offsets_size);
- m_newline_offsets_capacity = (that.m_newline_offsets_capacity);
- m_newline_offsets_buf = (that.m_newline_offsets_buf);
- that._clr();
- return *this;
-}
-
-Parser& Parser::operator=(Parser const& that)
-{
- _free();
- m_options = (that.m_options);
- m_file = (that.m_file);
- m_buf = (that.m_buf);
- m_root_id = (that.m_root_id);
- m_tree = (that.m_tree);
- m_stack = that.m_stack;
- m_state = &m_stack.top();
- m_key_tag_indentation = (that.m_key_tag_indentation);
- m_key_tag2_indentation = (that.m_key_tag2_indentation);
- m_key_tag = (that.m_key_tag);
- m_key_tag2 = (that.m_key_tag2);
- m_val_tag_indentation = (that.m_val_tag_indentation);
- m_val_tag = (that.m_val_tag);
- m_key_anchor_was_before = (that.m_key_anchor_was_before);
- m_key_anchor_indentation = (that.m_key_anchor_indentation);
- m_key_anchor = (that.m_key_anchor);
- m_val_anchor_indentation = (that.m_val_anchor_indentation);
- m_val_anchor = (that.m_val_anchor);
- if(that.m_filter_arena.len > 0)
- _resize_filter_arena(that.m_filter_arena.len);
- if(that.m_newline_offsets_capacity > m_newline_offsets_capacity)
- _resize_locations(that.m_newline_offsets_capacity);
- _RYML_CB_CHECK(m_stack.m_callbacks, m_newline_offsets_capacity >= that.m_newline_offsets_capacity);
- _RYML_CB_CHECK(m_stack.m_callbacks, m_newline_offsets_capacity >= that.m_newline_offsets_size);
- memcpy(m_newline_offsets, that.m_newline_offsets, that.m_newline_offsets_size * sizeof(size_t));
- m_newline_offsets_size = that.m_newline_offsets_size;
- m_newline_offsets_buf = that.m_newline_offsets_buf;
- return *this;
-}
-
-void Parser::_clr()
-{
- m_options = {};
- m_file = {};
- m_buf = {};
- m_root_id = {};
- m_tree = {};
- m_stack.clear();
- m_state = {};
- m_key_tag_indentation = {};
- m_key_tag2_indentation = {};
- m_key_tag = {};
- m_key_tag2 = {};
- m_val_tag_indentation = {};
- m_val_tag = {};
- m_key_anchor_was_before = {};
- m_key_anchor_indentation = {};
- m_key_anchor = {};
- m_val_anchor_indentation = {};
- m_val_anchor = {};
- m_filter_arena = {};
- m_newline_offsets = {};
- m_newline_offsets_size = {};
- m_newline_offsets_capacity = {};
- m_newline_offsets_buf = {};
-}
-
-void Parser::_free()
-{
- if(m_newline_offsets)
- {
- _RYML_CB_FREE(m_stack.m_callbacks, m_newline_offsets, size_t, m_newline_offsets_capacity);
- m_newline_offsets = nullptr;
- m_newline_offsets_size = 0u;
- m_newline_offsets_capacity = 0u;
- m_newline_offsets_buf = 0u;
- }
- if(m_filter_arena.len)
- {
- _RYML_CB_FREE(m_stack.m_callbacks, m_filter_arena.str, char, m_filter_arena.len);
- m_filter_arena = {};
- }
- m_stack._free();
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_reset()
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_stack.size() == 1);
- m_stack.clear();
- m_stack.push({});
- m_state = &m_stack.top();
- m_state->reset(m_file.str, m_root_id);
-
- m_key_tag_indentation = 0;
- m_key_tag2_indentation = 0;
- m_key_tag.clear();
- m_key_tag2.clear();
- m_val_tag_indentation = 0;
- m_val_tag.clear();
- m_key_anchor_was_before = false;
- m_key_anchor_indentation = 0;
- m_key_anchor.clear();
- m_val_anchor_indentation = 0;
- m_val_anchor.clear();
-
- if(m_options.locations())
- {
- _prepare_locations();
- }
-}
-
-//-----------------------------------------------------------------------------
-template<class DumpFn>
-void Parser::_fmt_msg(DumpFn &&dumpfn) const
-{
- auto const& lc = m_state->line_contents;
- csubstr contents = lc.stripped;
- if(contents.len)
- {
- // print the yaml src line
- size_t offs = 3u + to_chars(substr{}, m_state->pos.line) + to_chars(substr{}, m_state->pos.col);
- if(m_file.len)
- {
- _parse_dump(dumpfn, "{}:", m_file);
- offs += m_file.len + 1;
- }
- _parse_dump(dumpfn, "{}:{}: ", m_state->pos.line, m_state->pos.col);
- csubstr maybe_full_content = (contents.len < 80u ? contents : contents.first(80u));
- csubstr maybe_ellipsis = (contents.len < 80u ? csubstr{} : csubstr("..."));
- _parse_dump(dumpfn, "{}{} (size={})\n", maybe_full_content, maybe_ellipsis, contents.len);
- // highlight the remaining portion of the previous line
- size_t firstcol = (size_t)(lc.rem.begin() - lc.full.begin());
- size_t lastcol = firstcol + lc.rem.len;
- for(size_t i = 0; i < offs + firstcol; ++i)
- dumpfn(" ");
- dumpfn("^");
- for(size_t i = 1, e = (lc.rem.len < 80u ? lc.rem.len : 80u); i < e; ++i)
- dumpfn("~");
- _parse_dump(dumpfn, "{} (cols {}-{})\n", maybe_ellipsis, firstcol+1, lastcol+1);
- }
- else
- {
- dumpfn("\n");
- }
-
-#ifdef RYML_DBG
- // next line: print the state flags
- {
- char flagbuf_[64];
- _parse_dump(dumpfn, "top state: {}\n", _prfl(flagbuf_, m_state->flags));
- }
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-template<class ...Args>
-void Parser::_err(csubstr fmt, Args const& C4_RESTRICT ...args) const
-{
- char errmsg[RYML_ERRMSG_SIZE];
- detail::_SubstrWriter writer(errmsg);
- auto dumpfn = [&writer](csubstr s){ writer.append(s); };
- _parse_dump(dumpfn, fmt, args...);
- 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);
-}
-
-//-----------------------------------------------------------------------------
-#ifdef RYML_DBG
-template<class ...Args>
-void Parser::_dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const
-{
- auto dumpfn = [](csubstr s){ fwrite(s.str, 1, s.len, stdout); };
- _parse_dump(dumpfn, fmt, args...);
- dumpfn("\n");
- _fmt_msg(dumpfn);
-}
-#endif
-
-//-----------------------------------------------------------------------------
-bool Parser::_finished_file() const
-{
- bool ret = m_state->pos.offset >= m_buf.len;
- if(ret)
- {
- _c4dbgp("finished file!!!");
- }
- return ret;
-}
-
-//-----------------------------------------------------------------------------
-bool Parser::_finished_line() const
-{
- return m_state->line_contents.rem.empty();
-}
-
-//-----------------------------------------------------------------------------
-void Parser::parse_in_place(csubstr file, substr buf, Tree *t, size_t node_id)
-{
- m_file = file;
- m_buf = buf;
- m_root_id = node_id;
- m_tree = t;
- _reset();
- while( ! _finished_file())
- {
- _scan_line();
- while( ! _finished_line())
- _handle_line();
- if(_finished_file())
- break; // it may have finished because of multiline blocks
- _line_ended();
- }
- _handle_finished_file();
-}
-
-//-----------------------------------------------------------------------------
-void Parser::_handle_finished_file()
-{
- _end_stream();
-}
-
-//-----------------------------------------------------------------------------
-void Parser::_handle_line()
-{
- _c4dbgq("\n-----------");
- _c4dbgt("handling line={}, offset={}B", m_state->pos.line, m_state->pos.offset);
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! m_state->line_contents.rem.empty());
- if(has_any(RSEQ))
- {
- if(has_any(FLOW))
- {
- if(_handle_seq_flow())
- return;
- }
- else
- {
- if(_handle_seq_blck())
- return;
- }
- }
- else if(has_any(RMAP))
- {
- if(has_any(FLOW))
- {
- if(_handle_map_flow())
- return;
- }
- else
- {
- if(_handle_map_blck())
- return;
- }
- }
- else if(has_any(RUNK))
- {
- if(_handle_unk())
- return;
- }
-
- if(_handle_top())
- return;
-}
-
-
-//-----------------------------------------------------------------------------
-bool Parser::_handle_unk()
-{
- _c4dbgp("handle_unk");
-
- csubstr rem = m_state->line_contents.rem;
- const bool start_as_child = (node(m_state) == nullptr);
-
- if(C4_UNLIKELY(has_any(NDOC)))
- {
- if(rem == "---" || rem.begins_with("--- "))
- {
- _start_new_doc(rem);
- return true;
- }
- auto trimmed = rem.triml(' ');
- if(trimmed == "---" || trimmed.begins_with("--- "))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, rem.len >= trimmed.len);
- _line_progressed(rem.len - trimmed.len);
- _start_new_doc(trimmed);
- _save_indentation();
- return true;
- }
- else if(trimmed.begins_with("..."))
- {
- _end_stream();
- }
- else if(trimmed.first_of("#%") == csubstr::npos) // neither a doc nor a tag
- {
- _c4dbgpf("starting implicit doc to accomodate unexpected tokens: '{}'", rem);
- size_t indref = m_state->indref;
- _push_level();
- _start_doc();
- _set_indentation(indref);
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, !trimmed.empty());
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RNXT|RSEQ|RMAP));
- if(m_state->indref > 0)
- {
- csubstr ws = rem.left_of(rem.first_not_of(' '));
- if(m_state->indref <= ws.len)
- {
- _c4dbgpf("skipping base indentation of {}", m_state->indref);
- _line_progressed(m_state->indref);
- rem = rem.sub(m_state->indref);
- }
- }
-
- if(rem.begins_with("- ") _RYML_WITH_TAB_TOKENS( || rem.begins_with("-\t")))
- {
- _c4dbgpf("it's a seq (as_child={})", start_as_child);
- _move_key_anchor_to_val_anchor();
- _move_key_tag_to_val_tag();
- _push_level();
- _start_seq(start_as_child);
- _save_indentation();
- _line_progressed(2);
- return true;
- }
- else if(rem == '-')
- {
- _c4dbgpf("it's a seq (as_child={})", start_as_child);
- _move_key_anchor_to_val_anchor();
- _move_key_tag_to_val_tag();
- _push_level();
- _start_seq(start_as_child);
- _save_indentation();
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('['))
- {
- _c4dbgpf("it's a seq, flow (as_child={})", start_as_child);
- _move_key_anchor_to_val_anchor();
- _move_key_tag_to_val_tag();
- _push_level(/*explicit flow*/true);
- _start_seq(start_as_child);
- add_flags(FLOW);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('{'))
- {
- _c4dbgpf("it's a map, flow (as_child={})", start_as_child);
- _move_key_anchor_to_val_anchor();
- _move_key_tag_to_val_tag();
- _push_level(/*explicit flow*/true);
- _start_map(start_as_child);
- addrem_flags(FLOW|RKEY, RVAL);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with("? "))
- {
- _c4dbgpf("it's a map (as_child={}) + this key is complex", start_as_child);
- _move_key_anchor_to_val_anchor();
- _move_key_tag_to_val_tag();
- _push_level();
- _start_map(start_as_child);
- addrem_flags(RKEY|QMRK, RVAL);
- _save_indentation();
- _line_progressed(2);
- return true;
- }
- else if(rem.begins_with(": ") && !has_all(SSCL))
- {
- _c4dbgp("it's a map with an empty key");
- _move_key_anchor_to_val_anchor();
- _move_key_tag_to_val_tag();
- _push_level();
- _start_map(start_as_child);
- _store_scalar_null(rem.str);
- addrem_flags(RVAL, RKEY);
- _save_indentation();
- _line_progressed(2);
- return true;
- }
- else if(rem == ':' && !has_all(SSCL))
- {
- _c4dbgp("it's a map with an empty key");
- _move_key_anchor_to_val_anchor();
- _move_key_tag_to_val_tag();
- _push_level();
- _start_map(start_as_child);
- _store_scalar_null(rem.str);
- addrem_flags(RVAL, RKEY);
- _save_indentation();
- _line_progressed(1);
- return true;
- }
- else if(_handle_types())
- {
- return true;
- }
- else if(!rem.begins_with('*') && _handle_key_anchors_and_refs())
- {
- return true;
- }
- else if(has_all(SSCL))
- {
- _c4dbgpf("there's a stored scalar: '{}'", m_state->scalar);
-
- csubstr saved_scalar;
- bool is_quoted;
- if(_scan_scalar_unk(&saved_scalar, &is_quoted))
- {
- rem = m_state->line_contents.rem;
- _c4dbgpf("... and there's also a scalar next! '{}'", saved_scalar);
- if(rem.begins_with_any(" \t"))
- {
- size_t n = rem.first_not_of(" \t");
- _c4dbgpf("skipping {} spaces/tabs", n);
- rem = rem.sub(n);
- _line_progressed(n);
- }
- }
-
- _c4dbgpf("rem='{}'", rem);
-
- if(rem.begins_with(", "))
- {
- _c4dbgpf("got a ',' -- it's a seq (as_child={})", start_as_child);
- _start_seq(start_as_child);
- add_flags(FLOW);
- _append_val(_consume_scalar());
- _line_progressed(2);
- }
- else if(rem.begins_with(','))
- {
- _c4dbgpf("got a ',' -- it's a seq (as_child={})", start_as_child);
- _start_seq(start_as_child);
- add_flags(FLOW);
- _append_val(_consume_scalar());
- _line_progressed(1);
- }
- else if(rem.begins_with(": ") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t")))
- {
- _c4dbgpf("got a ': ' -- it's a map (as_child={})", start_as_child);
- _start_map_unk(start_as_child); // wait for the val scalar to append the key-val pair
- _line_progressed(2);
- }
- else if(rem == ":" || rem.begins_with(":\"") || rem.begins_with(":'"))
- {
- if(rem == ":") { _c4dbgpf("got a ':' -- it's a map (as_child={})", start_as_child); }
- else { _c4dbgpf("got a '{}' -- it's a map (as_child={})", rem.first(2), start_as_child); }
- _start_map_unk(start_as_child); // wait for the val scalar to append the key-val pair
- _line_progressed(1); // advance only 1
- }
- else if(rem.begins_with('}'))
- {
- if(!has_all(RMAP|FLOW))
- {
- _c4err("invalid token: not reading a map");
- }
- if(!has_all(SSCL))
- {
- _c4err("no scalar stored");
- }
- _append_key_val(saved_scalar);
- _stop_map();
- _line_progressed(1);
- }
- else if(rem.begins_with("..."))
- {
- _c4dbgp("got stream end '...'");
- _end_stream();
- _line_progressed(3);
- }
- else if(rem.begins_with('#'))
- {
- _c4dbgpf("it's a comment: '{}'", rem);
- _scan_comment();
- return true;
- }
- else if(_handle_key_anchors_and_refs())
- {
- return true;
- }
- else if(rem.begins_with(" ") || rem.begins_with("\t"))
- {
- size_t n = rem.first_not_of(" \t");
- if(n == npos)
- n = rem.len;
- _c4dbgpf("has {} spaces/tabs, skip...", n);
- _line_progressed(n);
- return true;
- }
- else if(rem.empty())
- {
- // nothing to do
- }
- else if(rem == "---" || rem.begins_with("--- "))
- {
- _c4dbgp("caught ---: starting doc");
- _start_new_doc(rem);
- return true;
- }
- else if(rem.begins_with('%'))
- {
- _c4dbgp("caught a directive: ignoring...");
- _line_progressed(rem.len);
- return true;
- }
- else
- {
- _c4err("parse error");
- }
-
- if( ! saved_scalar.empty())
- {
- _store_scalar(saved_scalar, is_quoted);
- }
-
- return true;
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! has_any(SSCL));
- csubstr scalar;
- size_t indentation = m_state->line_contents.indentation; // save
- bool is_quoted;
- if(_scan_scalar_unk(&scalar, &is_quoted))
- {
- _c4dbgpf("got a {} scalar", is_quoted ? "quoted" : "");
- rem = m_state->line_contents.rem;
- {
- size_t first = rem.first_not_of(" \t");
- if(first && first != npos)
- {
- _c4dbgpf("skip {} whitespace characters", first);
- _line_progressed(first);
- rem = rem.sub(first);
- }
- }
- _store_scalar(scalar, is_quoted);
- if(rem.begins_with(": ") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t")))
- {
- _c4dbgpf("got a ': ' next -- it's a map (as_child={})", start_as_child);
- _push_level();
- _start_map(start_as_child); // wait for the val scalar to append the key-val pair
- _set_indentation(indentation);
- _line_progressed(2); // call this AFTER saving the indentation
- }
- else if(rem == ":")
- {
- _c4dbgpf("got a ':' next -- it's a map (as_child={})", start_as_child);
- _push_level();
- _start_map(start_as_child); // wait for the val scalar to append the key-val pair
- _set_indentation(indentation);
- _line_progressed(1); // call this AFTER saving the indentation
- }
- else
- {
- // we still don't know whether it's a seq or a map
- // so just store the scalar
- }
- return true;
- }
- else if(rem.begins_with_any(" \t"))
- {
- csubstr ws = rem.left_of(rem.first_not_of(" \t"));
- rem = rem.right_of(ws);
- if(has_all(RTOP) && rem.begins_with("---"))
- {
- _c4dbgp("there's a doc starting, and it's indented");
- _set_indentation(ws.len);
- }
- _c4dbgpf("skipping {} spaces/tabs", ws.len);
- _line_progressed(ws.len);
- return true;
- }
- }
-
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-C4_ALWAYS_INLINE void Parser::_skipchars(char c)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->line_contents.rem.begins_with(c));
- size_t pos = m_state->line_contents.rem.first_not_of(c);
- if(pos == npos)
- pos = m_state->line_contents.rem.len; // maybe the line is just whitespace
- _c4dbgpf("skip {} '{}'", pos, c);
- _line_progressed(pos);
-}
-
-template<size_t N>
-C4_ALWAYS_INLINE void Parser::_skipchars(const char (&chars)[N])
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->line_contents.rem.begins_with_any(chars));
- size_t pos = m_state->line_contents.rem.first_not_of(chars);
- if(pos == npos)
- pos = m_state->line_contents.rem.len; // maybe the line is just whitespace
- _c4dbgpf("skip {} characters", pos);
- _line_progressed(pos);
-}
-
-
-//-----------------------------------------------------------------------------
-bool Parser::_handle_seq_flow()
-{
- _c4dbgpf("handle_seq_flow: node_id={} level={}", m_state->node_id, m_state->level);
- csubstr rem = m_state->line_contents.rem;
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RKEY));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(RSEQ|FLOW));
-
- if(rem.begins_with(' '))
- {
- // with explicit flow, indentation does not matter
- _c4dbgp("starts with spaces");
- _skipchars(' ');
- return true;
- }
- _RYML_WITH_TAB_TOKENS(else if(rem.begins_with('\t'))
- {
- _c4dbgp("starts with tabs");
- _skipchars('\t');
- return true;
- })
- else if(rem.begins_with('#'))
- {
- _c4dbgp("it's a comment");
- rem = _scan_comment(); // also progresses the line
- return true;
- }
- else if(rem.begins_with(']'))
- {
- _c4dbgp("end the sequence");
- _pop_level();
- _line_progressed(1);
- if(has_all(RSEQIMAP))
- {
- _stop_seqimap();
- _pop_level();
- }
- return true;
- }
-
- if(has_any(RVAL))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RNXT));
- bool is_quoted;
- if(_scan_scalar_seq_flow(&rem, &is_quoted))
- {
- _c4dbgp("it's a scalar");
- addrem_flags(RNXT, RVAL);
- _append_val(rem, is_quoted);
- return true;
- }
- else if(rem.begins_with('['))
- {
- _c4dbgp("val is a child seq");
- addrem_flags(RNXT, RVAL); // before _push_level!
- _push_level(/*explicit flow*/true);
- _start_seq();
- add_flags(FLOW);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('{'))
- {
- _c4dbgp("val is a child map");
- addrem_flags(RNXT, RVAL); // before _push_level!
- _push_level(/*explicit flow*/true);
- _start_map();
- addrem_flags(FLOW|RKEY, RVAL);
- _line_progressed(1);
- return true;
- }
- else if(rem == ':')
- {
- _c4dbgpf("found ':' -- there's an implicit map in the seq node[{}]", m_state->node_id);
- _start_seqimap();
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with(": ") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t")))
- {
- _c4dbgpf("found ': ' -- there's an implicit map in the seq node[{}]", m_state->node_id);
- _start_seqimap();
- _line_progressed(2);
- return true;
- }
- else if(rem.begins_with("? "))
- {
- _c4dbgpf("found '? ' -- there's an implicit map in the seq node[{}]", m_state->node_id);
- _start_seqimap();
- _line_progressed(2);
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(SSCL) && m_state->scalar == "");
- addrem_flags(QMRK|RKEY, RVAL|SSCL);
- return true;
- }
- else if(_handle_types())
- {
- return true;
- }
- else if(_handle_val_anchors_and_refs())
- {
- return true;
- }
- else if(rem.begins_with(", "))
- {
- _c4dbgp("found ',' -- the value was null");
- _append_val_null(rem.str - 1);
- _line_progressed(2);
- return true;
- }
- else if(rem.begins_with(','))
- {
- _c4dbgp("found ',' -- the value was null");
- _append_val_null(rem.str - 1);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('\t'))
- {
- _skipchars('\t');
- return true;
- }
- else
- {
- _c4err("parse error");
- }
- }
- else if(has_any(RNXT))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RVAL));
- if(rem.begins_with(", "))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(FLOW));
- _c4dbgp("seq: expect next val");
- addrem_flags(RVAL, RNXT);
- _line_progressed(2);
- return true;
- }
- else if(rem.begins_with(','))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(FLOW));
- _c4dbgp("seq: expect next val");
- addrem_flags(RVAL, RNXT);
- _line_progressed(1);
- return true;
- }
- else if(rem == ':')
- {
- _c4dbgpf("found ':' -- there's an implicit map in the seq node[{}]", m_state->node_id);
- _start_seqimap();
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with(": ") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t")))
- {
- _c4dbgpf("found ': ' -- there's an implicit map in the seq node[{}]", m_state->node_id);
- _start_seqimap();
- _line_progressed(2);
- return true;
- }
- else
- {
- _c4err("was expecting a comma");
- }
- }
- else
- {
- _c4err("internal error");
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-bool Parser::_handle_seq_blck()
-{
- _c4dbgpf("handle_seq_impl: node_id={} level={}", m_state->node_id, m_state->level);
- csubstr rem = m_state->line_contents.rem;
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(RSEQ));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RKEY));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(FLOW));
-
- if(rem.begins_with('#'))
- {
- _c4dbgp("it's a comment");
- rem = _scan_comment();
- return true;
- }
- if(has_any(RNXT))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RVAL));
-
- if(_handle_indentation())
- return true;
-
- if(rem.begins_with("- ") _RYML_WITH_TAB_TOKENS( || rem.begins_with("-\t")))
- {
- _c4dbgp("expect another val");
- addrem_flags(RVAL, RNXT);
- _line_progressed(2);
- return true;
- }
- else if(rem == '-')
- {
- _c4dbgp("expect another val");
- addrem_flags(RVAL, RNXT);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with_any(" \t"))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! _at_line_begin());
- _skipchars(" \t");
- return true;
- }
- else if(rem.begins_with("..."))
- {
- _c4dbgp("got stream end '...'");
- _end_stream();
- _line_progressed(3);
- return true;
- }
- else if(rem.begins_with("---"))
- {
- _c4dbgp("got document start '---'");
- _start_new_doc(rem);
- return true;
- }
- else
- {
- _c4err("parse error");
- }
- }
- else if(has_any(RVAL))
- {
- // there can be empty values
- if(_handle_indentation())
- return true;
-
- csubstr s;
- bool is_quoted;
- if(_scan_scalar_seq_blck(&s, &is_quoted)) // this also progresses the line
- {
- _c4dbgpf("it's a{} scalar", is_quoted ? " quoted" : "");
-
- rem = m_state->line_contents.rem;
- if(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(rem.begins_with_any(" \t"), rem.begins_with(' ')))
- {
- _c4dbgp("skipping whitespace...");
- size_t skip = rem.first_not_of(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' '));
- if(skip == csubstr::npos)
- skip = rem.len; // maybe the line is just whitespace
- _line_progressed(skip);
- rem = rem.sub(skip);
- }
-
- _c4dbgpf("rem=[{}]~~~{}~~~", rem.len, rem);
- if(!rem.begins_with('#') && (rem.ends_with(':') || rem.begins_with(": ") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t"))))
- {
- _c4dbgp("actually, the scalar is the first key of a map, and it opens a new scope");
- if(m_key_anchor.empty())
- _move_val_anchor_to_key_anchor();
- if(m_key_tag.empty())
- _move_val_tag_to_key_tag();
- addrem_flags(RNXT, RVAL); // before _push_level! This prepares the current level for popping by setting it to RNXT
- _push_level();
- _start_map();
- _store_scalar(s, is_quoted);
- if( ! _maybe_set_indentation_from_anchor_or_tag())
- {
- _c4dbgpf("set indentation from scalar: {}", m_state->scalar_col);
- _set_indentation(m_state->scalar_col); // this is the column where the scalar starts
- }
- _move_key_tag2_to_key_tag();
- addrem_flags(RVAL, RKEY);
- _line_progressed(1);
- }
- else
- {
- _c4dbgp("appending val to current seq");
- _append_val(s, is_quoted);
- addrem_flags(RNXT, RVAL);
- }
- return true;
- }
- else if(rem.begins_with("- ") _RYML_WITH_TAB_TOKENS( || rem.begins_with("-\t")))
- {
- if(_rval_dash_start_or_continue_seq())
- _line_progressed(2);
- return true;
- }
- else if(rem == '-')
- {
- if(_rval_dash_start_or_continue_seq())
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('['))
- {
- _c4dbgp("val is a child seq, flow");
- addrem_flags(RNXT, RVAL); // before _push_level!
- _push_level(/*explicit flow*/true);
- _start_seq();
- add_flags(FLOW);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('{'))
- {
- _c4dbgp("val is a child map, flow");
- addrem_flags(RNXT, RVAL); // before _push_level!
- _push_level(/*explicit flow*/true);
- _start_map();
- addrem_flags(FLOW|RKEY, RVAL);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with("? "))
- {
- _c4dbgp("val is a child map + this key is complex");
- addrem_flags(RNXT, RVAL); // before _push_level!
- _push_level();
- _start_map();
- addrem_flags(QMRK|RKEY, RVAL);
- _save_indentation();
- _line_progressed(2);
- return true;
- }
- else if(rem.begins_with(' '))
- {
- csubstr spc = rem.left_of(rem.first_not_of(' '));
- if(_at_line_begin())
- {
- _c4dbgpf("skipping value indentation: {} spaces", spc.len);
- _line_progressed(spc.len);
- return true;
- }
- else
- {
- _c4dbgpf("skipping {} spaces", spc.len);
- _line_progressed(spc.len);
- return true;
- }
- }
- else if(_handle_types())
- {
- return true;
- }
- else if(_handle_val_anchors_and_refs())
- {
- return true;
- }
- /* pathological case:
- * - &key : val
- * - &key :
- * - : val
- */
- else if((!has_all(SSCL)) &&
- (rem.begins_with(": ") || rem.left_of(rem.find("#")).trimr("\t") == ":"))
- {
- if(!m_val_anchor.empty() || !m_val_tag.empty())
- {
- _c4dbgp("val is a child map + this key is empty, with anchors or tags");
- addrem_flags(RNXT, RVAL); // before _push_level!
- _move_val_tag_to_key_tag();
- _move_val_anchor_to_key_anchor();
- _push_level();
- _start_map();
- _store_scalar_null(rem.str);
- addrem_flags(RVAL, RKEY);
- RYML_CHECK(_maybe_set_indentation_from_anchor_or_tag()); // one of them must exist
- _line_progressed(rem.begins_with(": ") ? 2u : 1u);
- return true;
- }
- else
- {
- _c4dbgp("val is a child map + this key is empty, no anchors or tags");
- addrem_flags(RNXT, RVAL); // before _push_level!
- size_t ind = m_state->indref;
- _push_level();
- _start_map();
- _store_scalar_null(rem.str);
- addrem_flags(RVAL, RKEY);
- _c4dbgpf("set indentation from map anchor: {}", ind + 2);
- _set_indentation(ind + 2); // this is the column where the map starts
- _line_progressed(rem.begins_with(": ") ? 2u : 1u);
- return true;
- }
- }
- else
- {
- _c4err("parse error");
- }
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-
-bool Parser::_rval_dash_start_or_continue_seq()
-{
- size_t ind = m_state->line_contents.current_col();
- _RYML_CB_ASSERT(m_stack.m_callbacks, ind >= m_state->indref);
- size_t delta_ind = ind - m_state->indref;
- if( ! delta_ind)
- {
- _c4dbgp("prev val was empty");
- addrem_flags(RNXT, RVAL);
- _append_val_null(&m_state->line_contents.full[ind]);
- return false;
- }
- _c4dbgp("val is a nested seq, indented");
- addrem_flags(RNXT, RVAL); // before _push_level!
- _push_level();
- _start_seq();
- _save_indentation();
- return true;
-}
-
-//-----------------------------------------------------------------------------
-bool Parser::_handle_map_flow()
-{
- // explicit flow, ie, inside {}, separated by commas
- _c4dbgpf("handle_map_flow: node_id={} level={}", m_state->node_id, m_state->level);
- csubstr rem = m_state->line_contents.rem;
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(RMAP|FLOW));
-
- if(rem.begins_with(' '))
- {
- // with explicit flow, indentation does not matter
- _c4dbgp("starts with spaces");
- _skipchars(' ');
- return true;
- }
- _RYML_WITH_TAB_TOKENS(else if(rem.begins_with('\t'))
- {
- // with explicit flow, indentation does not matter
- _c4dbgp("starts with tabs");
- _skipchars('\t');
- return true;
- })
- else if(rem.begins_with('#'))
- {
- _c4dbgp("it's a comment");
- rem = _scan_comment(); // also progresses the line
- return true;
- }
- else if(rem.begins_with('}'))
- {
- _c4dbgp("end the map");
- if(has_all(SSCL))
- {
- _c4dbgp("the last val was null");
- _append_key_val_null(rem.str - 1);
- rem_flags(RVAL);
- }
- _pop_level();
- _line_progressed(1);
- if(has_all(RSEQIMAP))
- {
- _c4dbgp("stopping implicitly nested 1x map");
- _stop_seqimap();
- _pop_level();
- }
- return true;
- }
-
- if(has_any(RNXT))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RKEY));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RVAL));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RSEQIMAP));
-
- if(rem.begins_with(", "))
- {
- _c4dbgp("seq: expect next keyval");
- addrem_flags(RKEY, RNXT);
- _line_progressed(2);
- return true;
- }
- else if(rem.begins_with(','))
- {
- _c4dbgp("seq: expect next keyval");
- addrem_flags(RKEY, RNXT);
- _line_progressed(1);
- return true;
- }
- else
- {
- _c4err("parse error");
- }
- }
- else if(has_any(RKEY))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RNXT));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RVAL));
-
- bool is_quoted;
- if(has_none(SSCL) && _scan_scalar_map_flow(&rem, &is_quoted))
- {
- _c4dbgp("it's a scalar");
- _store_scalar(rem, is_quoted);
- rem = m_state->line_contents.rem;
- csubstr trimmed = rem.triml(" \t");
- if(trimmed.len && (trimmed.begins_with(": ") || trimmed.begins_with_any(":,}") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t"))))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, trimmed.str >= rem.str);
- size_t num = static_cast<size_t>(trimmed.str - rem.str);
- _c4dbgpf("trimming {} whitespace after the scalar: '{}' --> '{}'", num, rem, rem.sub(num));
- rem = rem.sub(num);
- _line_progressed(num);
- }
- }
-
- if(rem.begins_with(": ") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t")))
- {
- _c4dbgp("wait for val");
- addrem_flags(RVAL, RKEY|QMRK);
- _line_progressed(2);
- if(!has_all(SSCL))
- {
- _c4dbgp("no key was found, defaulting to empty key ''");
- _store_scalar_null(rem.str);
- }
- return true;
- }
- else if(rem == ':')
- {
- _c4dbgp("wait for val");
- addrem_flags(RVAL, RKEY|QMRK);
- _line_progressed(1);
- if(!has_all(SSCL))
- {
- _c4dbgp("no key was found, defaulting to empty key ''");
- _store_scalar_null(rem.str);
- }
- return true;
- }
- else if(rem.begins_with('?'))
- {
- _c4dbgp("complex key");
- add_flags(QMRK);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with(','))
- {
- _c4dbgp("prev scalar was a key with null value");
- _append_key_val_null(rem.str - 1);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('}'))
- {
- _c4dbgp("map terminates after a key...");
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(SSCL));
- _c4dbgp("the last val was null");
- _append_key_val_null(rem.str - 1);
- rem_flags(RVAL);
- if(has_all(RSEQIMAP))
- {
- _c4dbgp("stopping implicitly nested 1x map");
- _stop_seqimap();
- _pop_level();
- }
- _pop_level();
- _line_progressed(1);
- return true;
- }
- else if(_handle_types())
- {
- return true;
- }
- else if(_handle_key_anchors_and_refs())
- {
- return true;
- }
- else if(rem == "")
- {
- return true;
- }
- else
- {
- size_t pos = rem.first_not_of(" \t");
- if(pos == csubstr::npos)
- pos = 0;
- rem = rem.sub(pos);
- if(rem.begins_with(':'))
- {
- _c4dbgp("wait for val");
- addrem_flags(RVAL, RKEY|QMRK);
- _line_progressed(pos + 1);
- if(!has_all(SSCL))
- {
- _c4dbgp("no key was found, defaulting to empty key ''");
- _store_scalar_null(rem.str);
- }
- return true;
- }
- else if(rem.begins_with('#'))
- {
- _c4dbgp("it's a comment");
- _line_progressed(pos);
- rem = _scan_comment(); // also progresses the line
- return true;
- }
- else
- {
- _c4err("parse error");
- }
- }
- }
- else if(has_any(RVAL))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RNXT));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RKEY));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(SSCL));
- bool is_quoted;
- if(_scan_scalar_map_flow(&rem, &is_quoted))
- {
- _c4dbgp("it's a scalar");
- addrem_flags(RNXT, RVAL|RKEY);
- _append_key_val(rem, is_quoted);
- if(has_all(RSEQIMAP))
- {
- _c4dbgp("stopping implicitly nested 1x map");
- _stop_seqimap();
- _pop_level();
- }
- return true;
- }
- else if(rem.begins_with('['))
- {
- _c4dbgp("val is a child seq");
- addrem_flags(RNXT, RVAL|RKEY); // before _push_level!
- _push_level(/*explicit flow*/true);
- _move_scalar_from_top();
- _start_seq();
- add_flags(FLOW);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('{'))
- {
- _c4dbgp("val is a child map");
- addrem_flags(RNXT, RVAL|RKEY); // before _push_level!
- _push_level(/*explicit flow*/true);
- _move_scalar_from_top();
- _start_map();
- addrem_flags(FLOW|RKEY, RNXT|RVAL);
- _line_progressed(1);
- return true;
- }
- else if(_handle_types())
- {
- return true;
- }
- else if(_handle_val_anchors_and_refs())
- {
- return true;
- }
- else if(rem.begins_with(','))
- {
- _c4dbgp("appending empty val");
- _append_key_val_null(rem.str - 1);
- addrem_flags(RKEY, RVAL);
- _line_progressed(1);
- if(has_any(RSEQIMAP))
- {
- _c4dbgp("stopping implicitly nested 1x map");
- _stop_seqimap();
- _pop_level();
- }
- return true;
- }
- else if(has_any(RSEQIMAP) && rem.begins_with(']'))
- {
- _c4dbgp("stopping implicitly nested 1x map");
- if(has_any(SSCL))
- {
- _append_key_val_null(rem.str - 1);
- }
- _stop_seqimap();
- _pop_level();
- return true;
- }
- else
- {
- _c4err("parse error");
- }
- }
- else
- {
- _c4err("internal error");
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-bool Parser::_handle_map_blck()
-{
- _c4dbgpf("handle_map_blck: node_id={} level={}", m_state->node_id, m_state->level);
- csubstr rem = m_state->line_contents.rem;
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(RMAP));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(FLOW));
-
- if(rem.begins_with('#'))
- {
- _c4dbgp("it's a comment");
- rem = _scan_comment();
- return true;
- }
-
- if(has_any(RNXT))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RKEY));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RVAL));
- // actually, we don't need RNXT in indent-based maps.
- addrem_flags(RKEY, RNXT);
- }
-
- if(_handle_indentation())
- {
- _c4dbgp("indentation token");
- return true;
- }
-
- if(has_any(RKEY))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RNXT));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RVAL));
-
- _c4dbgp("RMAP|RKEY read scalar?");
- bool is_quoted;
- if(_scan_scalar_map_blck(&rem, &is_quoted)) // this also progresses the line
- {
- _c4dbgpf("it's a{} scalar", is_quoted ? " quoted" : "");
- if(has_all(QMRK|SSCL))
- {
- _c4dbgpf("current key is QMRK; SSCL is set. so take store scalar='{}' as key and add an empty val", m_state->scalar);
- _append_key_val_null(rem.str - 1);
- }
- _store_scalar(rem, is_quoted);
- if(has_all(QMRK|RSET))
- {
- _c4dbgp("it's a complex key, so use null value '~'");
- _append_key_val_null(rem.str);
- }
- rem = m_state->line_contents.rem;
-
- if(rem.begins_with(':'))
- {
- _c4dbgp("wait for val");
- addrem_flags(RVAL, RKEY|QMRK);
- _line_progressed(1);
- rem = m_state->line_contents.rem;
- if(rem.begins_with_any(" \t"))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! _at_line_begin());
- rem = rem.left_of(rem.first_not_of(" \t"));
- _c4dbgpf("skip {} spaces/tabs", rem.len);
- _line_progressed(rem.len);
- }
- }
- return true;
- }
- else if(rem.begins_with_any(" \t"))
- {
- size_t pos = rem.first_not_of(" \t");
- if(pos == npos)
- pos = rem.len;
- _c4dbgpf("skip {} spaces/tabs", pos);
- _line_progressed(pos);
- return true;
- }
- else if(rem == '?' || rem.begins_with("? "))
- {
- _c4dbgp("it's a complex key");
- _line_progressed(rem.begins_with("? ") ? 2u : 1u);
- if(has_any(SSCL))
- _append_key_val_null(rem.str - 1);
- add_flags(QMRK);
- return true;
- }
- else if(has_all(QMRK) && rem.begins_with(':'))
- {
- _c4dbgp("complex key finished");
- if(!has_any(SSCL))
- _store_scalar_null(rem.str);
- addrem_flags(RVAL, RKEY|QMRK);
- _line_progressed(1);
- rem = m_state->line_contents.rem;
- if(rem.begins_with(' '))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! _at_line_begin());
- _skipchars(' ');
- }
- return true;
- }
- else if(rem == ':' || rem.begins_with(": ") _RYML_WITH_TAB_TOKENS( || rem.begins_with(":\t")))
- {
- _c4dbgp("key finished");
- if(!has_all(SSCL))
- {
- _c4dbgp("key was empty...");
- _store_scalar_null(rem.str);
- rem_flags(QMRK);
- }
- addrem_flags(RVAL, RKEY);
- _line_progressed(rem == ':' ? 1 : 2);
- return true;
- }
- else if(rem.begins_with("..."))
- {
- _c4dbgp("end current document");
- _end_stream();
- _line_progressed(3);
- return true;
- }
- else if(rem.begins_with("---"))
- {
- _c4dbgp("start new document '---'");
- _start_new_doc(rem);
- return true;
- }
- else if(_handle_types())
- {
- return true;
- }
- else if(_handle_key_anchors_and_refs())
- {
- return true;
- }
- else
- {
- _c4err("parse error");
- }
- }
- else if(has_any(RVAL))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RNXT));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RKEY));
-
- _c4dbgp("RMAP|RVAL read scalar?");
- csubstr s;
- bool is_quoted;
- if(_scan_scalar_map_blck(&s, &is_quoted)) // this also progresses the line
- {
- _c4dbgpf("it's a{} scalar", is_quoted ? " quoted" : "");
-
- rem = m_state->line_contents.rem;
-
- if(rem.begins_with(": "))
- {
- _c4dbgp("actually, the scalar is the first key of a map");
- addrem_flags(RKEY, RVAL); // before _push_level! This prepares the current level for popping by setting it to RNXT
- _push_level();
- _move_scalar_from_top();
- _move_val_anchor_to_key_anchor();
- _start_map();
- _save_indentation(m_state->scalar_col);
- addrem_flags(RVAL, RKEY);
- _line_progressed(2);
- }
- else if(rem.begins_with(':'))
- {
- _c4dbgp("actually, the scalar is the first key of a map, and it opens a new scope");
- addrem_flags(RKEY, RVAL); // before _push_level! This prepares the current level for popping by setting it to RNXT
- _push_level();
- _move_scalar_from_top();
- _move_val_anchor_to_key_anchor();
- _start_map();
- _save_indentation(/*behind*/s.len);
- addrem_flags(RVAL, RKEY);
- _line_progressed(1);
- }
- else
- {
- _c4dbgp("appending keyval to current map");
- _append_key_val(s, is_quoted);
- addrem_flags(RKEY, RVAL);
- }
- return true;
- }
- else if(rem.begins_with("- ") _RYML_WITH_TAB_TOKENS( || rem.begins_with("-\t")))
- {
- _c4dbgp("val is a nested seq, indented");
- addrem_flags(RKEY, RVAL); // before _push_level!
- _push_level();
- _move_scalar_from_top();
- _start_seq();
- _save_indentation();
- _line_progressed(2);
- return true;
- }
- else if(rem == '-')
- {
- _c4dbgp("maybe a seq. start unknown, indented");
- _start_unk();
- _save_indentation();
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('['))
- {
- _c4dbgp("val is a child seq, flow");
- addrem_flags(RKEY, RVAL); // before _push_level!
- _push_level(/*explicit flow*/true);
- _move_scalar_from_top();
- _start_seq();
- add_flags(FLOW);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with('{'))
- {
- _c4dbgp("val is a child map, flow");
- addrem_flags(RKEY, RVAL); // before _push_level!
- _push_level(/*explicit flow*/true);
- _move_scalar_from_top();
- _start_map();
- addrem_flags(FLOW|RKEY, RVAL);
- _line_progressed(1);
- return true;
- }
- else if(rem.begins_with(' '))
- {
- csubstr spc = rem.left_of(rem.first_not_of(' '));
- if(_at_line_begin())
- {
- _c4dbgpf("skipping value indentation: {} spaces", spc.len);
- _line_progressed(spc.len);
- return true;
- }
- else
- {
- _c4dbgpf("skipping {} spaces", spc.len);
- _line_progressed(spc.len);
- return true;
- }
- }
- else if(_handle_types())
- {
- return true;
- }
- else if(_handle_val_anchors_and_refs())
- {
- return true;
- }
- else if(rem.begins_with("--- ") || rem == "---" || rem.begins_with("---\t"))
- {
- _start_new_doc(rem);
- return true;
- }
- else if(rem.begins_with("..."))
- {
- _c4dbgp("end current document");
- _end_stream();
- _line_progressed(3);
- return true;
- }
- else
- {
- _c4err("parse error");
- }
- }
- else
- {
- _c4err("internal error");
- }
-
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-bool Parser::_handle_top()
-{
- _c4dbgp("handle_top");
- csubstr rem = m_state->line_contents.rem;
-
- if(rem.begins_with('#'))
- {
- _c4dbgp("a comment line");
- _scan_comment();
- return true;
- }
-
- csubstr trimmed = rem.triml(' ');
-
- if(trimmed.begins_with('%'))
- {
- _handle_directive(trimmed);
- _line_progressed(rem.len);
- return true;
- }
- else if(trimmed.begins_with("--- ") || trimmed == "---" || trimmed.begins_with("---\t"))
- {
- _start_new_doc(rem);
- if(trimmed.len < rem.len)
- {
- _line_progressed(rem.len - trimmed.len);
- _save_indentation();
- }
- return true;
- }
- else if(trimmed.begins_with("..."))
- {
- _c4dbgp("end current document");
- _end_stream();
- if(trimmed.len < rem.len)
- {
- _line_progressed(rem.len - trimmed.len);
- }
- _line_progressed(3);
- return true;
- }
- else
- {
- _c4err("parse error");
- }
-
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-
-bool Parser::_handle_key_anchors_and_refs()
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, !has_any(RVAL));
- const csubstr rem = m_state->line_contents.rem;
- if(rem.begins_with('&'))
- {
- _c4dbgp("found a key anchor!!!");
- if(has_all(QMRK|SSCL))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RKEY));
- _c4dbgp("there is a stored key, so this anchor is for the next element");
- _append_key_val_null(rem.str - 1);
- rem_flags(QMRK);
- return true;
- }
- csubstr anchor = rem.left_of(rem.first_of(' '));
- _line_progressed(anchor.len);
- anchor = anchor.sub(1); // skip the first character
- _move_key_anchor_to_val_anchor();
- _c4dbgpf("key anchor value: '{}'", anchor);
- m_key_anchor = anchor;
- m_key_anchor_indentation = m_state->line_contents.current_col(rem);
- return true;
- }
- else if(C4_UNLIKELY(rem.begins_with('*')))
- {
- _c4err("not implemented - this should have been catched elsewhere");
- C4_NEVER_REACH();
- return false;
- }
- return false;
-}
-
-bool Parser::_handle_val_anchors_and_refs()
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, !has_any(RKEY));
- const csubstr rem = m_state->line_contents.rem;
- if(rem.begins_with('&'))
- {
- csubstr anchor = rem.left_of(rem.first_of(' '));
- _line_progressed(anchor.len);
- anchor = anchor.sub(1); // skip the first character
- _c4dbgpf("val: found an anchor: '{}', indentation={}!!!", anchor, m_state->line_contents.current_col(rem));
- if(m_val_anchor.empty())
- {
- _c4dbgpf("save val anchor: '{}'", anchor);
- m_val_anchor = anchor;
- m_val_anchor_indentation = m_state->line_contents.current_col(rem);
- }
- else
- {
- _c4dbgpf("there is a pending val anchor '{}'", m_val_anchor);
- if(m_tree->is_seq(m_state->node_id))
- {
- if(m_tree->has_children(m_state->node_id))
- {
- _c4dbgpf("current node={} is a seq, has {} children", m_state->node_id, m_tree->num_children(m_state->node_id));
- _c4dbgpf("... so take the new one as a key anchor '{}'", anchor);
- m_key_anchor = anchor;
- m_key_anchor_indentation = m_state->line_contents.current_col(rem);
- }
- else
- {
- _c4dbgpf("current node={} is a seq, has no children", m_state->node_id);
- if(m_tree->has_val_anchor(m_state->node_id))
- {
- _c4dbgpf("... node={} already has val anchor: '{}'", m_state->node_id, m_tree->val_anchor(m_state->node_id));
- _c4dbgpf("... so take the new one as a key anchor '{}'", anchor);
- m_key_anchor = anchor;
- m_key_anchor_indentation = m_state->line_contents.current_col(rem);
- }
- else
- {
- _c4dbgpf("... so set pending val anchor: '{}' on current node {}", m_val_anchor, m_state->node_id);
- m_tree->set_val_anchor(m_state->node_id, m_val_anchor);
- m_val_anchor = anchor;
- m_val_anchor_indentation = m_state->line_contents.current_col(rem);
- }
- }
- }
- }
- return true;
- }
- else if(C4_UNLIKELY(rem.begins_with('*')))
- {
- _c4err("not implemented - this should have been catched elsewhere");
- C4_NEVER_REACH();
- return false;
- }
- return false;
-}
-
-void Parser::_move_key_anchor_to_val_anchor()
-{
- if(m_key_anchor.empty())
- return;
- _c4dbgpf("move current key anchor to val slot: key='{}' -> val='{}'", m_key_anchor, m_val_anchor);
- if(!m_val_anchor.empty())
- _c4err("triple-pending anchor");
- m_val_anchor = m_key_anchor;
- m_val_anchor_indentation = m_key_anchor_indentation;
- m_key_anchor = {};
- m_key_anchor_indentation = {};
-}
-
-void Parser::_move_val_anchor_to_key_anchor()
-{
- if(m_val_anchor.empty())
- return;
- if(!_token_is_from_this_line(m_val_anchor))
- return;
- _c4dbgpf("move current val anchor to key slot: key='{}' <- val='{}'", m_key_anchor, m_val_anchor);
- if(!m_key_anchor.empty())
- _c4err("triple-pending anchor");
- m_key_anchor = m_val_anchor;
- m_key_anchor_indentation = m_val_anchor_indentation;
- m_val_anchor = {};
- m_val_anchor_indentation = {};
-}
-
-void Parser::_move_key_tag_to_val_tag()
-{
- if(m_key_tag.empty())
- return;
- _c4dbgpf("move key tag to val tag: key='{}' -> val='{}'", m_key_tag, m_val_tag);
- m_val_tag = m_key_tag;
- m_val_tag_indentation = m_key_tag_indentation;
- m_key_tag.clear();
- m_key_tag_indentation = 0;
-}
-
-void Parser::_move_val_tag_to_key_tag()
-{
- if(m_val_tag.empty())
- return;
- if(!_token_is_from_this_line(m_val_tag))
- return;
- _c4dbgpf("move val tag to key tag: key='{}' <- val='{}'", m_key_tag, m_val_tag);
- m_key_tag = m_val_tag;
- m_key_tag_indentation = m_val_tag_indentation;
- m_val_tag.clear();
- m_val_tag_indentation = 0;
-}
-
-void Parser::_move_key_tag2_to_key_tag()
-{
- if(m_key_tag2.empty())
- return;
- _c4dbgpf("move key tag2 to key tag: key='{}' <- key2='{}'", m_key_tag, m_key_tag2);
- m_key_tag = m_key_tag2;
- m_key_tag_indentation = m_key_tag2_indentation;
- m_key_tag2.clear();
- m_key_tag2_indentation = 0;
-}
-
-
-//-----------------------------------------------------------------------------
-
-bool Parser::_handle_types()
-{
- csubstr rem = m_state->line_contents.rem.triml(' ');
- csubstr t;
-
- if(rem.begins_with("!!"))
- {
- _c4dbgp("begins with '!!'");
- t = rem.left_of(rem.first_of(" ,"));
- _RYML_CB_ASSERT(m_stack.m_callbacks, t.len >= 2);
- //t = t.sub(2);
- if(t == "!!set")
- add_flags(RSET);
- }
- else if(rem.begins_with("!<"))
- {
- _c4dbgp("begins with '!<'");
- t = rem.left_of(rem.first_of('>'), true);
- _RYML_CB_ASSERT(m_stack.m_callbacks, t.len >= 2);
- //t = t.sub(2, t.len-1);
- }
- else if(rem.begins_with("!h!"))
- {
- _c4dbgp("begins with '!h!'");
- t = rem.left_of(rem.first_of(' '));
- _RYML_CB_ASSERT(m_stack.m_callbacks, t.len >= 3);
- //t = t.sub(3);
- }
- else if(rem.begins_with('!'))
- {
- _c4dbgp("begins with '!'");
- t = rem.left_of(rem.first_of(' '));
- _RYML_CB_ASSERT(m_stack.m_callbacks, t.len >= 1);
- //t = t.sub(1);
- }
-
- if(t.empty())
- return false;
-
- if(has_all(QMRK|SSCL))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RKEY));
- _c4dbgp("there is a stored key, so this tag is for the next element");
- _append_key_val_null(rem.str - 1);
- rem_flags(QMRK);
- }
-
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- const char *tag_beginning = rem.str;
- #endif
- size_t tag_indentation = m_state->line_contents.current_col(t);
- _c4dbgpf("there was a tag: '{}', indentation={}", t, tag_indentation);
- _RYML_CB_ASSERT(m_stack.m_callbacks, t.end() > m_state->line_contents.rem.begin());
- _line_progressed(static_cast<size_t>(t.end() - m_state->line_contents.rem.begin()));
- {
- size_t pos = m_state->line_contents.rem.first_not_of(" \t");
- if(pos != csubstr::npos)
- _line_progressed(pos);
- }
-
- if(has_all(RMAP|RKEY))
- {
- _c4dbgpf("saving map key tag '{}'", t);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_key_tag.empty());
- m_key_tag = t;
- m_key_tag_indentation = tag_indentation;
- }
- else if(has_all(RMAP|RVAL))
- {
- /* foo: !!str
- * !!str : bar */
- rem = m_state->line_contents.rem;
- rem = rem.left_of(rem.find("#"));
- rem = rem.trimr(" \t");
- _c4dbgpf("rem='{}'", rem);
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- if(rem == ':' || rem.begins_with(": "))
- {
- _c4dbgp("the last val was null, and this is a tag from a null key");
- _append_key_val_null(tag_beginning - 1);
- _store_scalar_null(rem.str - 1);
- // do not change the flag to key, it is ~
- _RYML_CB_ASSERT(m_stack.m_callbacks, rem.begin() > m_state->line_contents.rem.begin());
- size_t token_len = rem == ':' ? 1 : 2;
- _line_progressed(static_cast<size_t>(token_len + rem.begin() - m_state->line_contents.rem.begin()));
- }
- #endif
- _c4dbgpf("saving map val tag '{}'", t);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_val_tag.empty());
- m_val_tag = t;
- m_val_tag_indentation = tag_indentation;
- }
- else if(has_all(RSEQ|RVAL) || has_all(RTOP|RUNK|NDOC))
- {
- if(m_val_tag.empty())
- {
- _c4dbgpf("saving seq/doc val tag '{}'", t);
- m_val_tag = t;
- m_val_tag_indentation = tag_indentation;
- }
- else
- {
- _c4dbgpf("saving seq/doc key tag '{}'", t);
- m_key_tag = t;
- m_key_tag_indentation = tag_indentation;
- }
- }
- else if(has_all(RTOP|RUNK) || has_any(RUNK))
- {
- rem = m_state->line_contents.rem;
- rem = rem.left_of(rem.find("#"));
- rem = rem.trimr(" \t");
- if(rem.empty())
- {
- _c4dbgpf("saving val tag '{}'", t);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_val_tag.empty());
- m_val_tag = t;
- m_val_tag_indentation = tag_indentation;
- }
- else
- {
- _c4dbgpf("saving key tag '{}'", t);
- if(m_key_tag.empty())
- {
- m_key_tag = t;
- m_key_tag_indentation = tag_indentation;
- }
- else
- {
- /* handle this case:
- * !!str foo: !!map
- * !!int 1: !!float 20.0
- * !!int 3: !!float 40.0
- *
- * (m_key_tag would be !!str and m_key_tag2 would be !!int)
- */
- m_key_tag2 = t;
- m_key_tag2_indentation = tag_indentation;
- }
- }
- }
- else
- {
- _c4err("internal error");
- }
-
- if(m_val_tag.not_empty())
- {
- YamlTag_e tag = to_tag(t);
- if(tag == TAG_STR)
- {
- _c4dbgpf("tag '{}' is a str-type tag", t);
- if(has_all(RTOP|RUNK|NDOC))
- {
- _c4dbgpf("docval. slurping the string. pos={}", m_state->pos.offset);
- csubstr scalar = _slurp_doc_scalar();
- _c4dbgpf("docval. after slurp: {}, at node {}: '{}'", m_state->pos.offset, m_state->node_id, scalar);
- m_tree->to_val(m_state->node_id, scalar, DOC);
- _c4dbgpf("docval. val tag {} -> {}", m_val_tag, normalize_tag(m_val_tag));
- m_tree->set_val_tag(m_state->node_id, normalize_tag(m_val_tag));
- m_val_tag.clear();
- if(!m_val_anchor.empty())
- {
- _c4dbgpf("setting val anchor[{}]='{}'", m_state->node_id, m_val_anchor);
- m_tree->set_val_anchor(m_state->node_id, m_val_anchor);
- m_val_anchor.clear();
- }
- _end_stream();
- }
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_slurp_doc_scalar()
-{
- csubstr s = m_state->line_contents.rem;
- size_t pos = m_state->pos.offset;
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->line_contents.full.find("---") != csubstr::npos);
- _c4dbgpf("slurp 0 '{}'. REM='{}'", s, m_buf.sub(m_state->pos.offset));
- if(s.len == 0)
- {
- _line_ended();
- _scan_line();
- s = m_state->line_contents.rem;
- pos = m_state->pos.offset;
- }
-
- size_t skipws = s.first_not_of(" \t");
- _c4dbgpf("slurp 1 '{}'. REM='{}'", s, m_buf.sub(m_state->pos.offset));
- if(skipws != npos)
- {
- _line_progressed(skipws);
- s = m_state->line_contents.rem;
- pos = m_state->pos.offset;
- _c4dbgpf("slurp 2 '{}'. REM='{}'", s, m_buf.sub(m_state->pos.offset));
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_val_anchor.empty());
- _handle_val_anchors_and_refs();
- if(!m_val_anchor.empty())
- {
- s = m_state->line_contents.rem;
- skipws = s.first_not_of(" \t");
- if(skipws != npos)
- {
- _line_progressed(skipws);
- }
- s = m_state->line_contents.rem;
- pos = m_state->pos.offset;
- _c4dbgpf("slurp 3 '{}'. REM='{}'", s, m_buf.sub(m_state->pos.offset));
- }
-
- if(s.begins_with('\''))
- {
- m_state->scalar_col = m_state->line_contents.current_col(s);
- return _scan_squot_scalar();
- }
- else if(s.begins_with('"'))
- {
- m_state->scalar_col = m_state->line_contents.current_col(s);
- return _scan_dquot_scalar();
- }
- else if(s.begins_with('|') || s.begins_with('>'))
- {
- return _scan_block();
- }
-
- _c4dbgpf("slurp 4 '{}'. REM='{}'", s, m_buf.sub(m_state->pos.offset));
-
- m_state->scalar_col = m_state->line_contents.current_col(s);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.end() >= m_buf.begin() + pos);
- _line_progressed(static_cast<size_t>(s.end() - (m_buf.begin() + pos)));
-
- _c4dbgpf("slurp 5 '{}'. REM='{}'", s, m_buf.sub(m_state->pos.offset));
-
- if(_at_line_end())
- {
- _c4dbgpf("at line end. curr='{}'", s);
- s = _extend_scanned_scalar(s);
- }
-
- _c4dbgpf("scalar was '{}'", s);
-
- return s;
-}
-
-
-//-----------------------------------------------------------------------------
-
-bool Parser::_scan_scalar_seq_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RSEQ));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RVAL));
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! has_any(RKEY));
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! has_any(FLOW));
-
- csubstr s = m_state->line_contents.rem;
- if(s.len == 0)
- return false;
- s = s.trim(" \t");
- if(s.len == 0)
- return false;
-
- if(s.begins_with('\''))
- {
- _c4dbgp("got a ': scanning single-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_squot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('"'))
- {
- _c4dbgp("got a \": scanning double-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_dquot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('|') || s.begins_with('>'))
- {
- *scalar = _scan_block();
- *quoted = true;
- return true;
- }
- else if(has_any(RTOP) && _is_doc_sep(s))
- {
- return false;
- }
-
- _c4dbgp("RSEQ|RVAL");
- if( ! _is_scalar_next__rseq_rval(s))
- return false;
- _RYML_WITH_TAB_TOKENS(else if(s.begins_with("-\t"))
- return false;
- )
-
- if(s.ends_with(':'))
- {
- --s.len;
- }
- else
- {
- auto first = s.first_of_any(": " _RYML_WITH_TAB_TOKENS( , ":\t"), " #");
- if(first)
- s.len = first.pos;
- }
- s = s.trimr(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' '));
-
- if(s.empty())
- return false;
-
- m_state->scalar_col = m_state->line_contents.current_col(s);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.str >= m_state->line_contents.rem.str);
- _line_progressed(static_cast<size_t>(s.str - m_state->line_contents.rem.str) + s.len);
-
- if(_at_line_end() && s != '~')
- {
- _c4dbgpf("at line end. curr='{}'", s);
- s = _extend_scanned_scalar(s);
- }
-
- _c4dbgpf("scalar was '{}'", s);
-
- *scalar = s;
- *quoted = false;
- return true;
-}
-
-bool Parser::_scan_scalar_map_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted)
-{
- _c4dbgp("_scan_scalar_map_blck");
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RMAP));
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! has_any(FLOW));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RKEY|RVAL));
-
- csubstr s = m_state->line_contents.rem;
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED__OR_REFACTORED
- if(s.len == 0)
- return false;
- #endif
- s = s.trim(" \t");
- if(s.len == 0)
- return false;
-
- if(s.begins_with('\''))
- {
- _c4dbgp("got a ': scanning single-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_squot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('"'))
- {
- _c4dbgp("got a \": scanning double-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_dquot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('|') || s.begins_with('>'))
- {
- *scalar = _scan_block();
- *quoted = true;
- return true;
- }
- else if(has_any(RTOP) && _is_doc_sep(s))
- {
- return false;
- }
-
- if( ! _is_scalar_next__rmap(s))
- return false;
-
- size_t colon_token = s.find(": ");
- if(colon_token == npos)
- {
- _RYML_WITH_OR_WITHOUT_TAB_TOKENS(
- // with tab tokens
- colon_token = s.find(":\t");
- if(colon_token == npos)
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len > 0);
- colon_token = s.find(':');
- if(colon_token != s.len-1)
- colon_token = npos;
- }
- ,
- // without tab tokens
- colon_token = s.find(':');
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len > 0);
- if(colon_token != s.len-1)
- colon_token = npos;
- )
- }
-
- if(has_all(RKEY))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, !s.begins_with(' '));
- if(has_any(QMRK))
- {
- _c4dbgp("RMAP|RKEY|CPLX");
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RMAP));
- if(s.begins_with("? ") || s == '?')
- return false;
- s = s.left_of(colon_token);
- s = s.left_of(s.first_of("#"));
- s = s.trimr(" \t");
- if(s.begins_with("---"))
- return false;
- else if(s.begins_with("..."))
- return false;
- }
- else
- {
- _c4dbgp("RMAP|RKEY");
- _RYML_CB_CHECK(m_stack.m_callbacks, !s.begins_with('{'));
- if(s.begins_with("? ") || s == '?')
- return false;
- s = s.left_of(colon_token);
- s = s.trimr(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' '));
- if(s.begins_with("---"))
- {
- return false;
- }
- else if(s.begins_with("..."))
- {
- return false;
- }
- }
- }
- else if(has_all(RVAL))
- {
- _c4dbgp("RMAP|RVAL");
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(QMRK));
- if( ! _is_scalar_next__rmap_val(s))
- return false;
- _RYML_WITH_TAB_TOKENS(
- else if(s.begins_with("-\t"))
- return false;
- )
- _c4dbgp("RMAP|RVAL: scalar");
- s = s.left_of(s.find(" #")); // is there a comment?
- s = s.left_of(s.find("\t#")); // is there a comment?
- s = s.trim(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' '));
- if(s.begins_with("---"))
- return false;
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED__OR_REFACTORED
- else if(s.begins_with("..."))
- return false;
- #endif
- }
-
- if(s.empty())
- return false;
-
- m_state->scalar_col = m_state->line_contents.current_col(s);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.str >= m_state->line_contents.rem.str);
- _line_progressed(static_cast<size_t>(s.str - m_state->line_contents.rem.str) + s.len);
-
- if(_at_line_end() && s != '~')
- {
- _c4dbgpf("at line end. curr='{}'", s);
- s = _extend_scanned_scalar(s);
- }
-
- _c4dbgpf("scalar was '{}'", s);
-
- *scalar = s;
- *quoted = false;
- return true;
-}
-
-bool Parser::_scan_scalar_seq_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RSEQ));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(FLOW));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RVAL));
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! has_any(RKEY));
-
- csubstr s = m_state->line_contents.rem;
- if(s.len == 0)
- return false;
- s = s.trim(" \t");
- if(s.len == 0)
- return false;
-
- if(s.begins_with('\''))
- {
- _c4dbgp("got a ': scanning single-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_squot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('"'))
- {
- _c4dbgp("got a \": scanning double-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_dquot_scalar();
- *quoted = true;
- return true;
- }
-
- if(has_all(RVAL))
- {
- _c4dbgp("RSEQ|RVAL");
- if( ! _is_scalar_next__rseq_rval(s))
- return false;
- _RYML_WITH_TAB_TOKENS(else if(s.begins_with("-\t"))
- return false;
- )
- _c4dbgp("RSEQ|RVAL|FLOW");
- s = s.left_of(s.first_of(",]"));
- if(s.ends_with(':'))
- {
- --s.len;
- }
- else
- {
- auto first = s.first_of_any(": " _RYML_WITH_TAB_TOKENS( , ":\t"), " #");
- if(first)
- s.len = first.pos;
- }
- s = s.trimr(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' '));
- }
-
- if(s.empty())
- return false;
-
- m_state->scalar_col = m_state->line_contents.current_col(s);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.str >= m_state->line_contents.rem.str);
- _line_progressed(static_cast<size_t>(s.str - m_state->line_contents.rem.str) + s.len);
-
- if(_at_line_end() && s != '~')
- {
- _c4dbgpf("at line end. curr='{}'", s);
- s = _extend_scanned_scalar(s);
- }
-
- _c4dbgpf("scalar was '{}'", s);
-
- *scalar = s;
- *quoted = false;
- return true;
-}
-
-bool Parser::_scan_scalar_map_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RMAP));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(FLOW));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RKEY|RVAL));
-
- csubstr s = m_state->line_contents.rem;
- if(s.len == 0)
- return false;
- s = s.trim(" \t");
- if(s.len == 0)
- return false;
-
- if(s.begins_with('\''))
- {
- _c4dbgp("got a ': scanning single-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_squot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('"'))
- {
- _c4dbgp("got a \": scanning double-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_dquot_scalar();
- *quoted = true;
- return true;
- }
-
- if( ! _is_scalar_next__rmap(s))
- return false;
-
- if(has_all(RKEY))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, !s.begins_with(' '));
- size_t colon_token = s.find(": ");
- if(colon_token == npos)
- {
- _RYML_WITH_OR_WITHOUT_TAB_TOKENS(
- // with tab tokens
- colon_token = s.find(":\t");
- if(colon_token == npos)
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len > 0);
- colon_token = s.find(':');
- if(colon_token != s.len-1)
- colon_token = npos;
- }
- ,
- // without tab tokens
- colon_token = s.find(':');
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len > 0);
- if(colon_token != s.len-1)
- colon_token = npos;
- )
- }
- if(s.begins_with("? ") || s == '?')
- return false;
- if(has_any(QMRK))
- {
- _c4dbgp("RMAP|RKEY|CPLX");
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RMAP));
- s = s.left_of(colon_token);
- s = s.left_of(s.first_of("#"));
- s = s.left_of(s.first_of(':'));
- s = s.trimr(" \t");
- if(s.begins_with("---"))
- return false;
- else if(s.begins_with("..."))
- return false;
- }
- else
- {
- _RYML_CB_CHECK(m_stack.m_callbacks, !s.begins_with('{'));
- _c4dbgp("RMAP|RKEY");
- s = s.left_of(colon_token);
- s = s.trimr(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' '));
- _c4dbgpf("RMAP|RKEY|FLOW: '{}'", s);
- s = s.left_of(s.first_of(",}"));
- if(s.ends_with(':'))
- --s.len;
- }
- }
- else if(has_all(RVAL))
- {
- _c4dbgp("RMAP|RVAL");
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(QMRK));
- if( ! _is_scalar_next__rmap_val(s))
- return false;
- _RYML_WITH_TAB_TOKENS(else if(s.begins_with("-\t"))
- return false;
- )
- _c4dbgp("RMAP|RVAL|FLOW");
- if(has_none(RSEQIMAP))
- s = s.left_of(s.first_of(",}"));
- else
- s = s.left_of(s.first_of(",]"));
- s = s.left_of(s.find(" #")); // is there a comment?
- s = s.left_of(s.find("\t#")); // is there a comment?
- s = s.trim(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' '));
- }
-
- if(s.empty())
- return false;
-
- m_state->scalar_col = m_state->line_contents.current_col(s);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.str >= m_state->line_contents.rem.str);
- _line_progressed(static_cast<size_t>(s.str - m_state->line_contents.rem.str) + s.len);
-
- if(_at_line_end() && s != '~')
- {
- _c4dbgpf("at line end. curr='{}'", s);
- s = _extend_scanned_scalar(s);
- }
-
- _c4dbgpf("scalar was '{}'", s);
-
- *scalar = s;
- *quoted = false;
- return true;
-}
-
-bool Parser::_scan_scalar_unk(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_any(RUNK));
-
- csubstr s = m_state->line_contents.rem;
- if(s.len == 0)
- return false;
- s = s.trim(" \t");
- if(s.len == 0)
- return false;
-
- if(s.begins_with('\''))
- {
- _c4dbgp("got a ': scanning single-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_squot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('"'))
- {
- _c4dbgp("got a \": scanning double-quoted scalar");
- m_state->scalar_col = m_state->line_contents.current_col(s);
- *scalar = _scan_dquot_scalar();
- *quoted = true;
- return true;
- }
- else if(s.begins_with('|') || s.begins_with('>'))
- {
- *scalar = _scan_block();
- *quoted = true;
- return true;
- }
- else if(has_any(RTOP) && _is_doc_sep(s))
- {
- return false;
- }
-
- _c4dbgpf("RUNK '[{}]~~~{}~~~", s.len, s);
- if( ! _is_scalar_next__runk(s))
- {
- _c4dbgp("RUNK: no scalar next");
- return false;
- }
- size_t pos = s.find(" #");
- if(pos != npos)
- s = s.left_of(pos);
- pos = s.find(": ");
- if(pos != npos)
- s = s.left_of(pos);
- else if(s.ends_with(':'))
- s = s.left_of(s.len-1);
- _RYML_WITH_TAB_TOKENS(
- else if((pos = s.find(":\t")) != npos) // TABS
- s = s.left_of(pos);
- )
- else
- s = s.left_of(s.first_of(','));
- s = s.trim(" \t");
- _c4dbgpf("RUNK: scalar='{}'", s);
-
- if(s.empty())
- return false;
-
- m_state->scalar_col = m_state->line_contents.current_col(s);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.str >= m_state->line_contents.rem.str);
- _line_progressed(static_cast<size_t>(s.str - m_state->line_contents.rem.str) + s.len);
-
- if(_at_line_end() && s != '~')
- {
- _c4dbgpf("at line end. curr='{}'", s);
- s = _extend_scanned_scalar(s);
- }
-
- _c4dbgpf("scalar was '{}'", s);
-
- *scalar = s;
- *quoted = false;
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-
-csubstr Parser::_extend_scanned_scalar(csubstr s)
-{
- if(has_all(RMAP|RKEY|QMRK))
- {
- size_t scalar_indentation = has_any(FLOW) ? 0 : m_state->scalar_col;
- _c4dbgpf("extend_scalar: explicit key! indref={} scalar_indentation={} scalar_col={}", m_state->indref, scalar_indentation, m_state->scalar_col);
- csubstr n = _scan_to_next_nonempty_line(scalar_indentation);
- if(!n.empty())
- {
- substr full = _scan_complex_key(s, n).trimr(" \t\r\n");
- if(full != s)
- s = _filter_plain_scalar(full, scalar_indentation);
- }
- }
- // deal with plain (unquoted) scalars that continue to the next line
- else if(!s.begins_with_any("*")) // cannot be a plain scalar if it starts with * (that's an anchor reference)
- {
- _c4dbgpf("extend_scalar: line ended, scalar='{}'", s);
- if(has_none(FLOW))
- {
- size_t scalar_indentation = m_state->indref + 1;
- if(has_all(RUNK) && scalar_indentation == 1)
- scalar_indentation = 0;
- csubstr n = _scan_to_next_nonempty_line(scalar_indentation);
- if(!n.empty())
- {
- _c4dbgpf("rscalar[IMPL]: state_indref={} state_indentation={} scalar_indentation={}", m_state->indref, m_state->line_contents.indentation, scalar_indentation);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->line_contents.full.is_super(n));
- substr full = _scan_plain_scalar_blck(s, n, scalar_indentation);
- if(full.len >= s.len)
- s = _filter_plain_scalar(full, scalar_indentation);
- }
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(FLOW));
- csubstr n = _scan_to_next_nonempty_line(/*indentation*/0);
- if(!n.empty())
- {
- _c4dbgp("rscalar[FLOW]");
- substr full = _scan_plain_scalar_flow(s, n);
- s = _filter_plain_scalar(full, /*indentation*/0);
- }
- }
- }
-
- return s;
-}
-
-
-//-----------------------------------------------------------------------------
-
-substr Parser::_scan_plain_scalar_flow(csubstr currscalar, csubstr peeked_line)
-{
- static constexpr const csubstr chars = "[]{}?#,";
- size_t pos = peeked_line.first_of(chars);
- bool first = true;
- while(pos != 0)
- {
- if(has_all(RMAP|RKEY) || has_any(RUNK))
- {
- csubstr tpkl = peeked_line.triml(' ').trimr("\r\n");
- if(tpkl.begins_with(": ") || tpkl == ':')
- {
- _c4dbgpf("rscalar[FLOW]: map value starts on the peeked line: '{}'", peeked_line);
- peeked_line = peeked_line.first(0);
- break;
- }
- else
- {
- auto colon_pos = peeked_line.first_of_any(": ", ":");
- if(colon_pos && colon_pos.pos < pos)
- {
- peeked_line = peeked_line.first(colon_pos.pos);
- _c4dbgpf("rscalar[FLOW]: found colon at {}. peeked='{}'", colon_pos.pos, peeked_line);
- _RYML_CB_ASSERT(m_stack.m_callbacks, peeked_line.end() >= m_state->line_contents.rem.begin());
- _line_progressed(static_cast<size_t>(peeked_line.end() - m_state->line_contents.rem.begin()));
- break;
- }
- }
- }
- if(pos != npos)
- {
- _c4dbgpf("rscalar[FLOW]: found special character '{}' at {}, stopping: '{}'", peeked_line[pos], pos, peeked_line.left_of(pos).trimr("\r\n"));
- peeked_line = peeked_line.left_of(pos);
- _RYML_CB_ASSERT(m_stack.m_callbacks, peeked_line.end() >= m_state->line_contents.rem.begin());
- _line_progressed(static_cast<size_t>(peeked_line.end() - m_state->line_contents.rem.begin()));
- break;
- }
- _c4dbgpf("rscalar[FLOW]: append another line, full: '{}'", peeked_line.trimr("\r\n"));
- if(!first)
- {
- RYML_CHECK(_advance_to_peeked());
- }
- peeked_line = _scan_to_next_nonempty_line(/*indentation*/0);
- if(peeked_line.empty())
- {
- _c4err("expected token or continuation");
- }
- pos = peeked_line.first_of(chars);
- first = false;
- }
- substr full(m_buf.str + (currscalar.str - m_buf.str), m_buf.begin() + m_state->pos.offset);
- full = full.trimr("\n\r ");
- return full;
-}
-
-
-//-----------------------------------------------------------------------------
-
-substr Parser::_scan_plain_scalar_blck(csubstr currscalar, csubstr peeked_line, size_t indentation)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.is_super(currscalar));
- // NOTE. there's a problem with _scan_to_next_nonempty_line(), as it counts newlines twice
- // size_t offs = m_state->pos.offset; // so we workaround by directly counting from the end of the given scalar
- _RYML_CB_ASSERT(m_stack.m_callbacks, currscalar.end() >= m_buf.begin());
- size_t offs = static_cast<size_t>(currscalar.end() - m_buf.begin());
- _RYML_CB_ASSERT(m_stack.m_callbacks, peeked_line.begins_with(' ', indentation));
- while(true)
- {
- _c4dbgpf("rscalar[IMPL]: continuing... ref_indentation={}", indentation);
- if(peeked_line.begins_with("...") || peeked_line.begins_with("---"))
- {
- _c4dbgpf("rscalar[IMPL]: document termination next -- bail now '{}'", peeked_line.trimr("\r\n"));
- break;
- }
- else if(( ! peeked_line.begins_with(' ', indentation))) // is the line deindented?
- {
- if(!peeked_line.trim(" \r\n\t").empty()) // is the line not blank?
- {
- _c4dbgpf("rscalar[IMPL]: deindented line, not blank -- bail now '{}'", peeked_line.trimr("\r\n"));
- break;
- }
- _c4dbgpf("rscalar[IMPL]: line is blank and has less indentation: ref={} line={}: '{}'", indentation, peeked_line.first_not_of(' ') == csubstr::npos ? 0 : peeked_line.first_not_of(' '), peeked_line.trimr("\r\n"));
- _c4dbgpf("rscalar[IMPL]: ... searching for a line starting at indentation {}", indentation);
- csubstr next_peeked = _scan_to_next_nonempty_line(indentation);
- if(next_peeked.empty())
- {
- _c4dbgp("rscalar[IMPL]: ... finished.");
- break;
- }
- _c4dbgp("rscalar[IMPL]: ... continuing.");
- peeked_line = next_peeked;
- }
-
- _c4dbgpf("rscalar[IMPL]: line contents: '{}'", peeked_line.right_of(indentation, true).trimr("\r\n"));
- size_t token_pos;
- if(peeked_line.find(": ") != npos)
- {
- _line_progressed(peeked_line.find(": "));
- _c4err("': ' is not a valid token in plain flow (unquoted) scalars");
- }
- else if(peeked_line.ends_with(':'))
- {
- _line_progressed(peeked_line.find(':'));
- _c4err("lines cannot end with ':' in plain flow (unquoted) scalars");
- }
- else if((token_pos = peeked_line.find(" #")) != npos)
- {
- _line_progressed(token_pos);
- break;
- //_c4err("' #' is not a valid token in plain flow (unquoted) scalars");
- }
-
- _c4dbgpf("rscalar[IMPL]: append another line: (len={})'{}'", peeked_line.len, peeked_line.trimr("\r\n"));
- if(!_advance_to_peeked())
- {
- _c4dbgp("rscalar[IMPL]: file finishes after the scalar");
- break;
- }
- peeked_line = m_state->line_contents.rem;
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.offset >= offs);
- substr full(m_buf.str + (currscalar.str - m_buf.str),
- currscalar.len + (m_state->pos.offset - offs));
- full = full.trimr("\r\n ");
- return full;
-}
-
-substr Parser::_scan_complex_key(csubstr currscalar, csubstr peeked_line)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.is_super(currscalar));
- // NOTE. there's a problem with _scan_to_next_nonempty_line(), as it counts newlines twice
- // size_t offs = m_state->pos.offset; // so we workaround by directly counting from the end of the given scalar
- _RYML_CB_ASSERT(m_stack.m_callbacks, currscalar.end() >= m_buf.begin());
- size_t offs = static_cast<size_t>(currscalar.end() - m_buf.begin());
- while(true)
- {
- _c4dbgp("rcplxkey: continuing...");
- if(peeked_line.begins_with("...") || peeked_line.begins_with("---"))
- {
- _c4dbgpf("rcplxkey: document termination next -- bail now '{}'", peeked_line.trimr("\r\n"));
- break;
- }
- else
- {
- size_t pos = peeked_line.first_of("?:[]{}");
- if(pos == csubstr::npos)
- {
- pos = peeked_line.find("- ");
- }
- if(pos != csubstr::npos)
- {
- _c4dbgpf("rcplxkey: found special characters at pos={}: '{}'", pos, peeked_line.trimr("\r\n"));
- _line_progressed(pos);
- break;
- }
- }
-
- _c4dbgpf("rcplxkey: no special chars found '{}'", peeked_line.trimr("\r\n"));
- csubstr next_peeked = _scan_to_next_nonempty_line(0);
- if(next_peeked.empty())
- {
- _c4dbgp("rcplxkey: empty ... finished.");
- break;
- }
- _c4dbgp("rcplxkey: ... continuing.");
- peeked_line = next_peeked;
-
- _c4dbgpf("rcplxkey: line contents: '{}'", peeked_line.trimr("\r\n"));
- size_t colpos;
- if((colpos = peeked_line.find(": ")) != npos)
- {
- _c4dbgp("rcplxkey: found ': ', stopping.");
- _line_progressed(colpos);
- break;
- }
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- else if((colpos = peeked_line.ends_with(':')))
- {
- _c4dbgp("rcplxkey: ends with ':', stopping.");
- _line_progressed(colpos);
- break;
- }
- #endif
- _c4dbgpf("rcplxkey: append another line: (len={})'{}'", peeked_line.len, peeked_line.trimr("\r\n"));
- if(!_advance_to_peeked())
- {
- _c4dbgp("rcplxkey: file finishes after the scalar");
- break;
- }
- peeked_line = m_state->line_contents.rem;
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.offset >= offs);
- substr full(m_buf.str + (currscalar.str - m_buf.str),
- currscalar.len + (m_state->pos.offset - offs));
- return full;
-}
-
-//! scans to the next non-blank line starting with the given indentation
-csubstr Parser::_scan_to_next_nonempty_line(size_t indentation)
-{
- csubstr next_peeked;
- while(true)
- {
- _c4dbgpf("rscalar: ... curr offset: {} indentation={}", m_state->pos.offset, indentation);
- next_peeked = _peek_next_line(m_state->pos.offset);
- csubstr next_peeked_triml = next_peeked.triml(' ');
- _c4dbgpf("rscalar: ... next peeked line='{}'", next_peeked.trimr("\r\n"));
- if(next_peeked_triml.begins_with('#'))
- {
- _c4dbgp("rscalar: ... first non-space character is #");
- return {};
- }
- else if(next_peeked.begins_with(' ', indentation))
- {
- _c4dbgpf("rscalar: ... begins at same indentation {}, assuming continuation", indentation);
- _advance_to_peeked();
- return next_peeked;
- }
- else // check for de-indentation
- {
- csubstr trimmed = next_peeked_triml.trimr("\t\r\n");
- _c4dbgpf("rscalar: ... deindented! trimmed='{}'", trimmed);
- if(!trimmed.empty())
- {
- _c4dbgp("rscalar: ... and not empty. bailing out.");
- return {};
- }
- }
- if(!_advance_to_peeked())
- {
- _c4dbgp("rscalar: file finished");
- return {};
- }
- }
- return {};
-}
-
-// returns false when the file finished
-bool Parser::_advance_to_peeked()
-{
- _line_progressed(m_state->line_contents.rem.len);
- _line_ended(); // advances to the peeked-at line, consuming all remaining (probably newline) characters on the current line
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->line_contents.rem.first_of("\r\n") == csubstr::npos);
- _c4dbgpf("advance to peeked: scan more... pos={} len={}", m_state->pos.offset, m_buf.len);
- _scan_line(); // puts the peeked-at line in the buffer
- if(_finished_file())
- {
- _c4dbgp("rscalar: finished file!");
- return false;
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-
-C4_ALWAYS_INLINE size_t _extend_from_combined_newline(char nl, char following)
-{
- return (nl == '\n' && following == '\r') || (nl == '\r' && following == '\n');
-}
-
-//! look for the next newline chars, and jump to the right of those
-csubstr from_next_line(csubstr rem)
-{
- size_t nlpos = rem.first_of("\r\n");
- if(nlpos == csubstr::npos)
- return {};
- const char nl = rem[nlpos];
- rem = rem.right_of(nlpos);
- if(rem.empty())
- return {};
- if(_extend_from_combined_newline(nl, rem.front()))
- rem = rem.sub(1);
- return rem;
-}
-
-csubstr Parser::_peek_next_line(size_t pos) const
-{
- csubstr rem{}; // declare here because of the goto
- size_t nlpos{}; // declare here because of the goto
- pos = pos == npos ? m_state->pos.offset : pos;
- if(pos >= m_buf.len)
- goto next_is_empty;
-
- // look for the next newline chars, and jump to the right of those
- rem = from_next_line(m_buf.sub(pos));
- if(rem.empty())
- goto next_is_empty;
-
- // now get everything up to and including the following newline chars
- nlpos = rem.first_of("\r\n");
- if((nlpos != csubstr::npos) && (nlpos + 1 < rem.len))
- nlpos += _extend_from_combined_newline(rem[nlpos], rem[nlpos+1]);
- rem = rem.left_of(nlpos, /*include_pos*/true);
-
- _c4dbgpf("peek next line @ {}: (len={})'{}'", pos, rem.len, rem.trimr("\r\n"));
- return rem;
-
-next_is_empty:
- _c4dbgpf("peek next line @ {}: (len=0)''", pos);
- return {};
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::LineContents::reset_with_next_line(csubstr buf, size_t offset)
-{
- RYML_ASSERT(offset <= buf.len);
- char const* C4_RESTRICT b = &buf[offset];
- char const* C4_RESTRICT e = b;
- // get the current line stripped of newline chars
- while(e < buf.end() && (*e != '\n' && *e != '\r'))
- ++e;
- RYML_ASSERT(e >= b);
- const csubstr stripped_ = buf.sub(offset, static_cast<size_t>(e - b));
- // advance pos to include the first line ending
- if(e != buf.end() && *e == '\r')
- ++e;
- if(e != buf.end() && *e == '\n')
- ++e;
- RYML_ASSERT(e >= b);
- const csubstr full_ = buf.sub(offset, static_cast<size_t>(e - b));
- reset(full_, stripped_);
-}
-
-void Parser::_scan_line()
-{
- if(m_state->pos.offset >= m_buf.len)
- {
- m_state->line_contents.reset(m_buf.last(0), m_buf.last(0));
- return;
- }
- m_state->line_contents.reset_with_next_line(m_buf, m_state->pos.offset);
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_line_progressed(size_t ahead)
-{
- _c4dbgpf("line[{}] ({} cols) progressed by {}: col {}-->{} offset {}-->{}", m_state->pos.line, m_state->line_contents.full.len, ahead, m_state->pos.col, m_state->pos.col+ahead, m_state->pos.offset, m_state->pos.offset+ahead);
- m_state->pos.offset += ahead;
- m_state->pos.col += ahead;
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.col <= m_state->line_contents.stripped.len+1);
- m_state->line_contents.rem = m_state->line_contents.rem.sub(ahead);
-}
-
-void Parser::_line_ended()
-{
- _c4dbgpf("line[{}] ({} cols) ended! offset {}-->{}", m_state->pos.line, m_state->line_contents.full.len, m_state->pos.offset, m_state->pos.offset+m_state->line_contents.full.len - m_state->line_contents.stripped.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.col == m_state->line_contents.stripped.len+1);
- m_state->pos.offset += m_state->line_contents.full.len - m_state->line_contents.stripped.len;
- ++m_state->pos.line;
- m_state->pos.col = 1;
-}
-
-void Parser::_line_ended_undo()
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.col == 1u);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.line > 0u);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.offset >= m_state->line_contents.full.len - m_state->line_contents.stripped.len);
- size_t delta = m_state->line_contents.full.len - m_state->line_contents.stripped.len;
- _c4dbgpf("line[{}] undo ended! line {}-->{}, offset {}-->{}", m_state->pos.line, m_state->pos.line, m_state->pos.line - 1, m_state->pos.offset, m_state->pos.offset - delta);
- m_state->pos.offset -= delta;
- --m_state->pos.line;
- m_state->pos.col = m_state->line_contents.stripped.len + 1u;
- // don't forget to undo also the changes to the remainder of the line
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.offset >= m_buf.len || m_buf[m_state->pos.offset] == '\n' || m_buf[m_state->pos.offset] == '\r');
- m_state->line_contents.rem = m_buf.sub(m_state->pos.offset, 0);
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_set_indentation(size_t indentation)
-{
- m_state->indref = indentation;
- _c4dbgpf("state[{}]: saving indentation: {}", m_state-m_stack.begin(), m_state->indref);
-}
-
-void Parser::_save_indentation(size_t behind)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->line_contents.rem.begin() >= m_state->line_contents.full.begin());
- m_state->indref = static_cast<size_t>(m_state->line_contents.rem.begin() - m_state->line_contents.full.begin());
- _RYML_CB_ASSERT(m_stack.m_callbacks, behind <= m_state->indref);
- m_state->indref -= behind;
- _c4dbgpf("state[{}]: saving indentation: {}", m_state-m_stack.begin(), m_state->indref);
-}
-
-bool Parser::_maybe_set_indentation_from_anchor_or_tag()
-{
- if(m_key_anchor.not_empty())
- {
- _c4dbgpf("set indentation from key anchor: {}", m_key_anchor_indentation);
- _set_indentation(m_key_anchor_indentation); // this is the column where the anchor starts
- return true;
- }
- else if(m_key_tag.not_empty())
- {
- _c4dbgpf("set indentation from key tag: {}", m_key_tag_indentation);
- _set_indentation(m_key_tag_indentation); // this is the column where the tag starts
- return true;
- }
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_write_key_anchor(size_t node_id)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->has_key(node_id));
- if( ! m_key_anchor.empty())
- {
- _c4dbgpf("node={}: set key anchor to '{}'", node_id, m_key_anchor);
- m_tree->set_key_anchor(node_id, m_key_anchor);
- m_key_anchor.clear();
- m_key_anchor_was_before = false;
- m_key_anchor_indentation = 0;
- }
- else if( ! m_tree->is_key_quoted(node_id))
- {
- csubstr r = m_tree->key(node_id);
- if(r.begins_with('*'))
- {
- _c4dbgpf("node={}: set key reference: '{}'", node_id, r);
- m_tree->set_key_ref(node_id, r.sub(1));
- }
- else if(r == "<<")
- {
- m_tree->set_key_ref(node_id, r);
- _c4dbgpf("node={}: it's an inheriting reference", node_id);
- if(m_tree->is_seq(node_id))
- {
- _c4dbgpf("node={}: inheriting from seq of {}", node_id, m_tree->num_children(node_id));
- for(size_t i = m_tree->first_child(node_id); i != NONE; i = m_tree->next_sibling(i))
- {
- if( ! (m_tree->val(i).begins_with('*')))
- _c4err("malformed reference: '{}'", m_tree->val(i));
- }
- }
- else if( ! m_tree->val(node_id).begins_with('*'))
- {
- _c4err("malformed reference: '{}'", m_tree->val(node_id));
- }
- //m_tree->set_key_ref(node_id, r);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-void Parser::_write_val_anchor(size_t node_id)
-{
- if( ! m_val_anchor.empty())
- {
- _c4dbgpf("node={}: set val anchor to '{}'", node_id, m_val_anchor);
- m_tree->set_val_anchor(node_id, m_val_anchor);
- m_val_anchor.clear();
- }
- csubstr r = m_tree->has_val(node_id) ? m_tree->val(node_id) : "";
- if(!m_tree->is_val_quoted(node_id) && r.begins_with('*'))
- {
- _c4dbgpf("node={}: set val reference: '{}'", node_id, r);
- RYML_CHECK(!m_tree->has_val_anchor(node_id));
- m_tree->set_val_ref(node_id, r.sub(1));
- }
-}
-
-//-----------------------------------------------------------------------------
-void Parser::_push_level(bool explicit_flow_chars)
-{
- _c4dbgpf("pushing level! currnode={} currlevel={} stacksize={} stackcap={}", m_state->node_id, m_state->level, m_stack.size(), m_stack.capacity());
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state == &m_stack.top());
- if(node(m_state) == nullptr)
- {
- _c4dbgp("pushing level! actually no, current node is null");
- //_RYML_CB_ASSERT(m_stack.m_callbacks, ! explicit_flow_chars);
- return;
- }
- flag_t st = RUNK;
- if(explicit_flow_chars || has_all(FLOW))
- {
- st |= FLOW;
- }
- m_stack.push_top();
- m_state = &m_stack.top();
- set_flags(st);
- m_state->node_id = (size_t)NONE;
- m_state->indref = (size_t)NONE;
- ++m_state->level;
- _c4dbgpf("pushing level: now, currlevel={}", m_state->level);
-}
-
-void Parser::_pop_level()
-{
- _c4dbgpf("popping level! currnode={} currlevel={}", m_state->node_id, m_state->level);
- if(has_any(RMAP) || m_tree->is_map(m_state->node_id))
- {
- _stop_map();
- }
- if(has_any(RSEQ) || m_tree->is_seq(m_state->node_id))
- {
- _stop_seq();
- }
- if(m_tree->is_doc(m_state->node_id))
- {
- _stop_doc();
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_stack.size() > 1);
- _prepare_pop();
- m_stack.pop();
- m_state = &m_stack.top();
- /*if(has_any(RMAP))
- {
- _toggle_key_val();
- }*/
- if(m_state->line_contents.indentation == 0)
- {
- //_RYML_CB_ASSERT(m_stack.m_callbacks, has_none(RTOP));
- add_flags(RTOP);
- }
- _c4dbgpf("popping level: now, currnode={} currlevel={}", m_state->node_id, m_state->level);
-}
-
-//-----------------------------------------------------------------------------
-void Parser::_start_unk(bool /*as_child*/)
-{
- _c4dbgp("start_unk");
- _push_level();
- _move_scalar_from_top();
-}
-
-//-----------------------------------------------------------------------------
-void Parser::_start_doc(bool as_child)
-{
- _c4dbgpf("start_doc (as child={})", as_child);
- _RYML_CB_ASSERT(m_stack.m_callbacks, node(m_stack.bottom()) == node(m_root_id));
- size_t parent_id = m_stack.size() < 2 ? m_root_id : m_stack.top(1).node_id;
- _RYML_CB_ASSERT(m_stack.m_callbacks, parent_id != NONE);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_root(parent_id));
- _RYML_CB_ASSERT(m_stack.m_callbacks, node(m_state) == nullptr || node(m_state) == node(m_root_id));
- if(as_child)
- {
- _c4dbgpf("start_doc: parent={}", parent_id);
- if( ! m_tree->is_stream(parent_id))
- {
- _c4dbgp("start_doc: rearranging with root as STREAM");
- m_tree->set_root_as_stream();
- }
- m_state->node_id = m_tree->append_child(parent_id);
- m_tree->to_doc(m_state->node_id);
- }
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_seq(parent_id) || m_tree->empty(parent_id));
- m_state->node_id = parent_id;
- if( ! m_tree->is_doc(parent_id))
- {
- m_tree->to_doc(parent_id, DOC);
- }
- }
- #endif
- _c4dbgpf("start_doc: id={}", m_state->node_id);
- add_flags(RUNK|RTOP|NDOC);
- _handle_types();
- rem_flags(NDOC);
-}
-
-void Parser::_stop_doc()
-{
- size_t doc_node = m_state->node_id;
- _c4dbgpf("stop_doc[{}]", doc_node);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_doc(doc_node));
- if(!m_tree->is_seq(doc_node) && !m_tree->is_map(doc_node) && !m_tree->is_val(doc_node))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(SSCL));
- _c4dbgpf("stop_doc[{}]: there was nothing; adding null val", doc_node);
- m_tree->to_val(doc_node, {}, DOC);
- }
-}
-
-void Parser::_end_stream()
-{
- _c4dbgpf("end_stream, level={} node_id={}", m_state->level, m_state->node_id);
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! m_stack.empty());
- NodeData *added = nullptr;
- if(has_any(SSCL))
- {
- if(m_tree->is_seq(m_state->node_id))
- {
- _c4dbgp("append val...");
- added = _append_val(_consume_scalar());
- }
- else if(m_tree->is_map(m_state->node_id))
- {
- _c4dbgp("append null key val...");
- added = _append_key_val_null(m_state->line_contents.rem.str);
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- if(has_any(RSEQIMAP))
- {
- _stop_seqimap();
- _pop_level();
- }
- #endif
- }
- else if(m_tree->is_doc(m_state->node_id) || m_tree->type(m_state->node_id) == NOTYPE)
- {
- NodeType_e quoted = has_any(QSCL) ? VALQUO : NOTYPE; // do this before consuming the scalar
- csubstr scalar = _consume_scalar();
- _c4dbgpf("node[{}]: to docval '{}'{}", m_state->node_id, scalar, quoted == VALQUO ? ", quoted" : "");
- m_tree->to_val(m_state->node_id, scalar, DOC|quoted);
- added = m_tree->get(m_state->node_id);
- }
- else
- {
- _c4err("internal error");
- }
- }
- else if(has_all(RSEQ|RVAL) && has_none(FLOW))
- {
- _c4dbgp("add last...");
- added = _append_val_null(m_state->line_contents.rem.str);
- }
- else if(!m_val_tag.empty() && (m_tree->is_doc(m_state->node_id) || m_tree->type(m_state->node_id) == NOTYPE))
- {
- csubstr scalar = m_state->line_contents.rem.first(0);
- _c4dbgpf("node[{}]: add null scalar as docval", m_state->node_id);
- m_tree->to_val(m_state->node_id, scalar, DOC);
- added = m_tree->get(m_state->node_id);
- }
-
- if(added)
- {
- size_t added_id = m_tree->id(added);
- if(m_tree->is_seq(m_state->node_id) || m_tree->is_doc(m_state->node_id))
- {
- if(!m_key_anchor.empty())
- {
- _c4dbgpf("node[{}]: move key to val anchor: '{}'", added_id, m_key_anchor);
- m_val_anchor = m_key_anchor;
- m_key_anchor = {};
- }
- if(!m_key_tag.empty())
- {
- _c4dbgpf("node[{}]: move key to val tag: '{}'", added_id, m_key_tag);
- m_val_tag = m_key_tag;
- m_key_tag = {};
- }
- }
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- if(!m_key_anchor.empty())
- {
- _c4dbgpf("node[{}]: set key anchor='{}'", added_id, m_key_anchor);
- m_tree->set_key_anchor(added_id, m_key_anchor);
- m_key_anchor = {};
- }
- #endif
- if(!m_val_anchor.empty())
- {
- _c4dbgpf("node[{}]: set val anchor='{}'", added_id, m_val_anchor);
- m_tree->set_val_anchor(added_id, m_val_anchor);
- m_val_anchor = {};
- }
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- if(!m_key_tag.empty())
- {
- _c4dbgpf("node[{}]: set key tag='{}' -> '{}'", added_id, m_key_tag, normalize_tag(m_key_tag));
- m_tree->set_key_tag(added_id, normalize_tag(m_key_tag));
- m_key_tag = {};
- }
- #endif
- if(!m_val_tag.empty())
- {
- _c4dbgpf("node[{}]: set val tag='{}' -> '{}'", added_id, m_val_tag, normalize_tag(m_val_tag));
- m_tree->set_val_tag(added_id, normalize_tag(m_val_tag));
- m_val_tag = {};
- }
- }
-
- while(m_stack.size() > 1)
- {
- _c4dbgpf("popping level: {} (stack sz={})", m_state->level, m_stack.size());
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! has_any(SSCL, &m_stack.top()));
- if(has_all(RSEQ|FLOW))
- _err("closing ] not found");
- _pop_level();
- }
- add_flags(NDOC);
-}
-
-void Parser::_start_new_doc(csubstr rem)
-{
- _c4dbgp("_start_new_doc");
- _RYML_CB_ASSERT(m_stack.m_callbacks, rem.begins_with("---"));
- C4_UNUSED(rem);
-
- _end_stream();
-
- size_t indref = m_state->indref;
- _c4dbgpf("start a document, indentation={}", indref);
- _line_progressed(3);
- _push_level();
- _start_doc();
- _set_indentation(indref);
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_start_map(bool as_child)
-{
- _c4dbgpf("start_map (as child={})", as_child);
- addrem_flags(RMAP|RVAL, RKEY|RUNK);
- _RYML_CB_ASSERT(m_stack.m_callbacks, node(m_stack.bottom()) == node(m_root_id));
- size_t parent_id = m_stack.size() < 2 ? m_root_id : m_stack.top(1).node_id;
- _RYML_CB_ASSERT(m_stack.m_callbacks, parent_id != NONE);
- _RYML_CB_ASSERT(m_stack.m_callbacks, node(m_state) == nullptr || node(m_state) == node(m_root_id));
- if(as_child)
- {
- m_state->node_id = m_tree->append_child(parent_id);
- if(has_all(SSCL))
- {
- type_bits key_quoted = NOTYPE;
- if(m_state->flags & QSCL) // before consuming the scalar
- key_quoted |= KEYQUO;
- csubstr key = _consume_scalar();
- m_tree->to_map(m_state->node_id, key, key_quoted);
- _c4dbgpf("start_map: id={} key='{}'", m_state->node_id, m_tree->key(m_state->node_id));
- _write_key_anchor(m_state->node_id);
- if( ! m_key_tag.empty())
- {
- _c4dbgpf("node[{}]: set key tag='{}' -> '{}'", m_state->node_id, m_key_tag, normalize_tag(m_key_tag));
- m_tree->set_key_tag(m_state->node_id, normalize_tag(m_key_tag));
- m_key_tag.clear();
- }
- }
- else
- {
- m_tree->to_map(m_state->node_id);
- _c4dbgpf("start_map: id={}", m_state->node_id);
- }
- m_tree->_p(m_state->node_id)->m_val.scalar.str = m_state->line_contents.rem.str;
- _write_val_anchor(m_state->node_id);
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, parent_id != NONE);
- m_state->node_id = parent_id;
- _c4dbgpf("start_map: id={}", m_state->node_id);
- type_bits as_doc = 0;
- if(m_tree->is_doc(m_state->node_id))
- as_doc |= DOC;
- if(!m_tree->is_map(parent_id))
- {
- RYML_CHECK(!m_tree->has_children(parent_id));
- m_tree->to_map(parent_id, as_doc);
- }
- else
- {
- m_tree->_add_flags(parent_id, as_doc);
- }
- _move_scalar_from_top();
- if(m_key_anchor.not_empty())
- m_key_anchor_was_before = true;
- _write_val_anchor(parent_id);
- if(m_stack.size() >= 2)
- {
- State const& parent_state = m_stack.top(1);
- if(parent_state.flags & RSET)
- add_flags(RSET);
- }
- m_tree->_p(parent_id)->m_val.scalar.str = m_state->line_contents.rem.str;
- }
- if( ! m_val_tag.empty())
- {
- _c4dbgpf("node[{}]: set val tag='{}' -> '{}'", m_state->node_id, m_val_tag, normalize_tag(m_val_tag));
- m_tree->set_val_tag(m_state->node_id, normalize_tag(m_val_tag));
- m_val_tag.clear();
- }
-}
-
-void Parser::_start_map_unk(bool as_child)
-{
- if(!m_key_anchor_was_before)
- {
- _c4dbgpf("stash key anchor before starting map... '{}'", m_key_anchor);
- csubstr ka = m_key_anchor;
- m_key_anchor = {};
- _start_map(as_child);
- m_key_anchor = ka;
- }
- else
- {
- _start_map(as_child);
- m_key_anchor_was_before = false;
- }
- if(m_key_tag2.not_empty())
- {
- m_key_tag = m_key_tag2;
- m_key_tag_indentation = m_key_tag2_indentation;
- m_key_tag2.clear();
- m_key_tag2_indentation = 0;
- }
-}
-
-void Parser::_stop_map()
-{
- _c4dbgpf("stop_map[{}]", m_state->node_id);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_map(m_state->node_id));
- if(has_all(QMRK|RKEY) && !has_all(SSCL))
- {
- _c4dbgpf("stop_map[{}]: RKEY", m_state->node_id);
- _store_scalar_null(m_state->line_contents.rem.str);
- _append_key_val_null(m_state->line_contents.rem.str);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_start_seq(bool as_child)
-{
- _c4dbgpf("start_seq (as child={})", as_child);
- if(has_all(RTOP|RUNK))
- {
- _c4dbgpf("start_seq: moving key tag to val tag: '{}'", m_key_tag);
- m_val_tag = m_key_tag;
- m_key_tag.clear();
- }
- addrem_flags(RSEQ|RVAL, RUNK);
- _RYML_CB_ASSERT(m_stack.m_callbacks, node(m_stack.bottom()) == node(m_root_id));
- size_t parent_id = m_stack.size() < 2 ? m_root_id : m_stack.top(1).node_id;
- _RYML_CB_ASSERT(m_stack.m_callbacks, parent_id != NONE);
- _RYML_CB_ASSERT(m_stack.m_callbacks, node(m_state) == nullptr || node(m_state) == node(m_root_id));
- if(as_child)
- {
- m_state->node_id = m_tree->append_child(parent_id);
- if(has_all(SSCL))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_map(parent_id));
- type_bits key_quoted = 0;
- if(m_state->flags & QSCL) // before consuming the scalar
- key_quoted |= KEYQUO;
- csubstr key = _consume_scalar();
- m_tree->to_seq(m_state->node_id, key, key_quoted);
- _c4dbgpf("start_seq: id={} name='{}'", m_state->node_id, m_tree->key(m_state->node_id));
- _write_key_anchor(m_state->node_id);
- if( ! m_key_tag.empty())
- {
- _c4dbgpf("start_seq[{}]: set key tag='{}' -> '{}'", m_state->node_id, m_key_tag, normalize_tag(m_key_tag));
- m_tree->set_key_tag(m_state->node_id, normalize_tag(m_key_tag));
- m_key_tag.clear();
- }
- }
- else
- {
- type_bits as_doc = 0;
- _RYML_CB_ASSERT(m_stack.m_callbacks, !m_tree->is_doc(m_state->node_id));
- m_tree->to_seq(m_state->node_id, as_doc);
- _c4dbgpf("start_seq: id={}{}", m_state->node_id, as_doc ? " as doc" : "");
- }
- _write_val_anchor(m_state->node_id);
- m_tree->_p(m_state->node_id)->m_val.scalar.str = m_state->line_contents.rem.str;
- }
- else
- {
- m_state->node_id = parent_id;
- type_bits as_doc = 0;
- if(m_tree->is_doc(m_state->node_id))
- as_doc |= DOC;
- if(!m_tree->is_seq(parent_id))
- {
- RYML_CHECK(!m_tree->has_children(parent_id));
- m_tree->to_seq(parent_id, as_doc);
- }
- else
- {
- m_tree->_add_flags(parent_id, as_doc);
- }
- _move_scalar_from_top();
- _c4dbgpf("start_seq: id={}{}", m_state->node_id, as_doc ? " as_doc" : "");
- _write_val_anchor(parent_id);
- m_tree->_p(parent_id)->m_val.scalar.str = m_state->line_contents.rem.str;
- }
- if( ! m_val_tag.empty())
- {
- _c4dbgpf("start_seq[{}]: set val tag='{}' -> '{}'", m_state->node_id, m_val_tag, normalize_tag(m_val_tag));
- m_tree->set_val_tag(m_state->node_id, normalize_tag(m_val_tag));
- m_val_tag.clear();
- }
-}
-
-void Parser::_stop_seq()
-{
- _c4dbgp("stop_seq");
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_seq(m_state->node_id));
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_start_seqimap()
-{
- _c4dbgpf("start_seqimap at node={}. has_children={}", m_state->node_id, m_tree->has_children(m_state->node_id));
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(RSEQ|FLOW));
- // create a map, and turn the last scalar of this sequence
- // into the key of the map's first child. This scalar was
- // understood to be a value in the sequence, but it is
- // actually a key of a map, implicitly opened here.
- // Eg [val, key: val]
- //
- // Yep, YAML is crazy.
- if(m_tree->has_children(m_state->node_id) && m_tree->has_val(m_tree->last_child(m_state->node_id)))
- {
- size_t prev = m_tree->last_child(m_state->node_id);
- NodeType ty = m_tree->_p(prev)->m_type; // don't use type() because it masks out the quotes
- NodeScalar tmp = m_tree->valsc(prev);
- _c4dbgpf("has children and last child={} has val. saving the scalars, val='{}' quoted={}", prev, tmp.scalar, ty.is_val_quoted());
- m_tree->remove(prev);
- _push_level();
- _start_map();
- _store_scalar(tmp.scalar, ty.is_val_quoted());
- m_key_anchor = tmp.anchor;
- m_key_tag = tmp.tag;
- }
- else
- {
- _c4dbgpf("node {} has no children yet, using empty key", m_state->node_id);
- _push_level();
- _start_map();
- _store_scalar_null(m_state->line_contents.rem.str);
- }
- add_flags(RSEQIMAP|FLOW);
-}
-
-void Parser::_stop_seqimap()
-{
- _c4dbgp("stop_seqimap");
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(RSEQIMAP));
-}
-
-
-//-----------------------------------------------------------------------------
-NodeData* Parser::_append_val(csubstr val, flag_t quoted)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, ! has_all(SSCL));
- _RYML_CB_ASSERT(m_stack.m_callbacks, node(m_state) != nullptr);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_seq(m_state->node_id));
- type_bits additional_flags = quoted ? VALQUO : NOTYPE;
- _c4dbgpf("append val: '{}' to parent id={} (level={}){}", val, m_state->node_id, m_state->level, quoted ? " VALQUO!" : "");
- size_t nid = m_tree->append_child(m_state->node_id);
- m_tree->to_val(nid, val, additional_flags);
-
- _c4dbgpf("append val: id={} val='{}'", nid, m_tree->get(nid)->m_val.scalar);
- if( ! m_val_tag.empty())
- {
- _c4dbgpf("append val[{}]: set val tag='{}' -> '{}'", nid, m_val_tag, normalize_tag(m_val_tag));
- m_tree->set_val_tag(nid, normalize_tag(m_val_tag));
- m_val_tag.clear();
- }
- _write_val_anchor(nid);
- return m_tree->get(nid);
-}
-
-NodeData* Parser::_append_key_val(csubstr val, flag_t val_quoted)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_map(m_state->node_id));
- type_bits additional_flags = 0;
- if(m_state->flags & QSCL)
- additional_flags |= KEYQUO;
- if(val_quoted)
- additional_flags |= VALQUO;
-
- csubstr key = _consume_scalar();
- _c4dbgpf("append keyval: '{}' '{}' to parent id={} (level={}){}{}", key, val, m_state->node_id, m_state->level, (additional_flags & KEYQUO) ? " KEYQUO!" : "", (additional_flags & VALQUO) ? " VALQUO!" : "");
- size_t nid = m_tree->append_child(m_state->node_id);
- m_tree->to_keyval(nid, key, val, additional_flags);
- _c4dbgpf("append keyval: id={} key='{}' val='{}'", nid, m_tree->key(nid), m_tree->val(nid));
- if( ! m_key_tag.empty())
- {
- _c4dbgpf("append keyval[{}]: set key tag='{}' -> '{}'", nid, m_key_tag, normalize_tag(m_key_tag));
- m_tree->set_key_tag(nid, normalize_tag(m_key_tag));
- m_key_tag.clear();
- }
- if( ! m_val_tag.empty())
- {
- _c4dbgpf("append keyval[{}]: set val tag='{}' -> '{}'", nid, m_val_tag, normalize_tag(m_val_tag));
- m_tree->set_val_tag(nid, normalize_tag(m_val_tag));
- m_val_tag.clear();
- }
- _write_key_anchor(nid);
- _write_val_anchor(nid);
- rem_flags(QMRK);
- return m_tree->get(nid);
-}
-
-
-//-----------------------------------------------------------------------------
-void Parser::_store_scalar(csubstr s, flag_t is_quoted)
-{
- _c4dbgpf("state[{}]: storing scalar '{}' (flag: {}) (old scalar='{}')",
- m_state-m_stack.begin(), s, m_state->flags & SSCL, m_state->scalar);
- RYML_CHECK(has_none(SSCL));
- add_flags(SSCL | (is_quoted * QSCL));
- m_state->scalar = s;
-}
-
-csubstr Parser::_consume_scalar()
-{
- _c4dbgpf("state[{}]: consuming scalar '{}' (flag: {}))", m_state-m_stack.begin(), m_state->scalar, m_state->flags & SSCL);
- RYML_CHECK(m_state->flags & SSCL);
- csubstr s = m_state->scalar;
- rem_flags(SSCL | QSCL);
- m_state->scalar.clear();
- return s;
-}
-
-void Parser::_move_scalar_from_top()
-{
- if(m_stack.size() < 2) return;
- State &prev = m_stack.top(1);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state == &m_stack.top());
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state != &prev);
- if(prev.flags & SSCL)
- {
- _c4dbgpf("moving scalar '{}' from state[{}] to state[{}] (overwriting '{}')", prev.scalar, &prev-m_stack.begin(), m_state-m_stack.begin(), m_state->scalar);
- add_flags(prev.flags & (SSCL | QSCL));
- m_state->scalar = prev.scalar;
- rem_flags(SSCL | QSCL, &prev);
- prev.scalar.clear();
- }
-}
-
-//-----------------------------------------------------------------------------
-/** @todo this function is a monster and needs love. Likely, it needs
- * to be split like _scan_scalar_*() */
-bool Parser::_handle_indentation()
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(FLOW));
- if( ! _at_line_begin())
- return false;
-
- size_t ind = m_state->line_contents.indentation;
- csubstr rem = m_state->line_contents.rem;
- /** @todo instead of trimming, we should use the indentation index from above */
- csubstr remt = rem.triml(' ');
-
- if(remt.empty() || remt.begins_with('#')) // this is a blank or comment line
- {
- _line_progressed(rem.size());
- return true;
- }
-
- _c4dbgpf("indentation? ind={} indref={}", ind, m_state->indref);
- if(ind == m_state->indref)
- {
- _c4dbgpf("same indentation: {}", ind);
- if(!rem.sub(ind).begins_with('-'))
- {
- _c4dbgp("does not begin with -");
- if(has_any(RMAP))
- {
- if(has_all(SSCL|RVAL))
- {
- _c4dbgp("add with null val");
- _append_key_val_null(rem.str + ind - 1);
- addrem_flags(RKEY, RVAL);
- }
- }
- else if(has_any(RSEQ))
- {
- if(m_stack.size() > 2) // do not pop to root level
- {
- if(has_any(RNXT))
- {
- _c4dbgp("end the indentless seq");
- _pop_level();
- return true;
- }
- else if(has_any(RVAL))
- {
- _c4dbgp("add with null val");
- _append_val_null(rem.str);
- _c4dbgp("end the indentless seq");
- _pop_level();
- return true;
- }
- }
- }
- }
- _line_progressed(ind);
- return ind > 0;
- }
- else if(ind < m_state->indref)
- {
- _c4dbgpf("smaller indentation ({} < {})!!!", ind, m_state->indref);
- if(has_all(RVAL))
- {
- _c4dbgp("there was an empty val -- appending");
- if(has_all(RMAP))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_all(SSCL));
- _append_key_val_null(rem.sub(ind).str - 1);
- }
- else if(has_all(RSEQ))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, has_none(SSCL));
- _append_val_null(rem.sub(ind).str - 1);
- }
- }
- // search the stack frame to jump to based on its indentation
- State const* popto = nullptr;
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_stack.is_contiguous()); // this search relies on the stack being contiguous
- for(State const* s = m_state-1; s >= m_stack.begin(); --s)
- {
- _c4dbgpf("searching for state with indentation {}. curr={} (level={},node={})", ind, s->indref, s->level, s->node_id);
- if(s->indref == ind)
- {
- _c4dbgpf("gotit!!! level={} node={}", s->level, s->node_id);
- popto = s;
- // while it may be tempting to think we're done at this
- // point, we must still determine whether we're jumping to a
- // parent with the same indentation. Consider this case with
- // an indentless sequence:
- //
- // product:
- // - sku: BL394D
- // quantity: 4
- // description: Basketball
- // price: 450.00
- // - sku: BL4438H
- // quantity: 1
- // description: Super Hoop
- // price: 2392.00 # jumping one level here would be wrong.
- // tax: 1234.5 # we must jump two levels
- if(popto > m_stack.begin())
- {
- auto parent = popto - 1;
- if(parent->indref == popto->indref)
- {
- _c4dbgpf("the parent (level={},node={}) has the same indentation ({}). is this in an indentless sequence?", parent->level, parent->node_id, popto->indref);
- _c4dbgpf("isseq(popto)={} ismap(parent)={}", m_tree->is_seq(popto->node_id), m_tree->is_map(parent->node_id));
- if(m_tree->is_seq(popto->node_id) && m_tree->is_map(parent->node_id))
- {
- if( ! remt.begins_with('-'))
- {
- _c4dbgp("this is an indentless sequence");
- popto = parent;
- }
- else
- {
- _c4dbgp("not an indentless sequence");
- }
- }
- }
- }
- break;
- }
- }
- if(!popto || popto >= m_state || popto->level >= m_state->level)
- {
- _c4err("parse error: incorrect indentation?");
- }
- _c4dbgpf("popping {} levels: from level {} to level {}", m_state->level-popto->level, m_state->level, popto->level);
- while(m_state != popto)
- {
- _c4dbgpf("popping level {} (indentation={})", m_state->level, m_state->indref);
- _pop_level();
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, ind == m_state->indref);
- _line_progressed(ind);
- return true;
- }
- else
- {
- _c4dbgpf("larger indentation ({} > {})!!!", ind, m_state->indref);
- _RYML_CB_ASSERT(m_stack.m_callbacks, ind > m_state->indref);
- if(has_all(RMAP|RVAL))
- {
- if(_is_scalar_next__rmap_val(remt) && remt.first_of(":?") == npos)
- {
- _c4dbgpf("actually it seems a value: '{}'", remt);
- }
- else
- {
- addrem_flags(RKEY, RVAL);
- _start_unk();
- //_move_scalar_from_top();
- _line_progressed(ind);
- _save_indentation();
- return true;
- }
- }
- else if(has_all(RSEQ|RVAL))
- {
- // nothing to do here
- }
- else
- {
- _c4err("parse error - indentation should not increase at this point");
- }
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_scan_comment()
-{
- csubstr s = m_state->line_contents.rem;
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.begins_with('#'));
- _line_progressed(s.len);
- // skip the # character
- s = s.sub(1);
- // skip leading whitespace
- s = s.right_of(s.first_not_of(' '), /*include_pos*/true);
- _c4dbgpf("comment was '{}'", s);
- return s;
-}
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_scan_squot_scalar()
-{
- // quoted scalars can spread over multiple lines!
- // nice explanation here: http://yaml-multiline.info/
-
- // a span to the end of the file
- size_t b = m_state->pos.offset;
- substr s = m_buf.sub(b);
- if(s.begins_with(' '))
- {
- s = s.triml(' ');
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.sub(b).is_super(s));
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.begin() >= m_buf.sub(b).begin());
- _line_progressed((size_t)(s.begin() - m_buf.sub(b).begin()));
- }
- b = m_state->pos.offset; // take this into account
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.begins_with('\''));
-
- // skip the opening quote
- _line_progressed(1);
- s = s.sub(1);
-
- bool needs_filter = false;
-
- size_t numlines = 1; // we already have one line
- size_t pos = npos; // find the pos of the matching quote
- while( ! _finished_file())
- {
- const csubstr line = m_state->line_contents.rem;
- bool line_is_blank = true;
- _c4dbgpf("scanning single quoted scalar @ line[{}]: ~~~{}~~~", m_state->pos.line, line);
- for(size_t i = 0; i < line.len; ++i)
- {
- const char curr = line.str[i];
- if(curr == '\'') // single quotes are escaped with two single quotes
- {
- const char next = i+1 < line.len ? line.str[i+1] : '~';
- if(next != '\'') // so just look for the first quote
- { // without another after it
- pos = i;
- break;
- }
- else
- {
- needs_filter = true; // needs filter to remove escaped quotes
- ++i; // skip the escaped quote
- }
- }
- else if(curr != ' ')
- {
- line_is_blank = false;
- }
- }
-
- // leading whitespace also needs filtering
- needs_filter = needs_filter
- || (numlines > 1)
- || line_is_blank
- || (_at_line_begin() && line.begins_with(' '));
-
- if(pos == npos)
- {
- _line_progressed(line.len);
- ++numlines;
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos >= 0 && pos < m_buf.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf[m_state->pos.offset + pos] == '\'');
- _line_progressed(pos + 1); // progress beyond the quote
- pos = m_state->pos.offset - b - 1; // but we stop before it
- break;
- }
-
- _line_ended();
- _scan_line();
- }
-
- if(pos == npos)
- {
- _c4err("reached end of file while looking for closing quote");
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos > 0);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.end() >= m_buf.begin() && s.end() <= m_buf.end());
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.end() == m_buf.end() || *s.end() == '\'');
- s = s.sub(0, pos-1);
- }
-
- if(needs_filter)
- {
- csubstr ret = _filter_squot_scalar(s);
- _RYML_CB_ASSERT(m_stack.m_callbacks, ret.len <= s.len || s.empty() || s.trim(' ').empty());
- _c4dbgpf("final scalar: \"{}\"", ret);
- return ret;
- }
-
- _c4dbgpf("final scalar: \"{}\"", s);
-
- return s;
-}
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_scan_dquot_scalar()
-{
- // quoted scalars can spread over multiple lines!
- // nice explanation here: http://yaml-multiline.info/
-
- // a span to the end of the file
- size_t b = m_state->pos.offset;
- substr s = m_buf.sub(b);
- if(s.begins_with(' '))
- {
- s = s.triml(' ');
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.sub(b).is_super(s));
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.begin() >= m_buf.sub(b).begin());
- _line_progressed((size_t)(s.begin() - m_buf.sub(b).begin()));
- }
- b = m_state->pos.offset; // take this into account
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.begins_with('"'));
-
- // skip the opening quote
- _line_progressed(1);
- s = s.sub(1);
-
- bool needs_filter = false;
-
- size_t numlines = 1; // we already have one line
- size_t pos = npos; // find the pos of the matching quote
- while( ! _finished_file())
- {
- const csubstr line = m_state->line_contents.rem;
- bool line_is_blank = true;
- _c4dbgpf("scanning double quoted scalar @ line[{}]: line='{}'", m_state->pos.line, line);
- for(size_t i = 0; i < line.len; ++i)
- {
- const char curr = line.str[i];
- if(curr != ' ')
- line_is_blank = false;
- // every \ is an escape
- if(curr == '\\')
- {
- const char next = i+1 < line.len ? line.str[i+1] : '~';
- needs_filter = true;
- if(next == '"' || next == '\\')
- ++i;
- }
- else if(curr == '"')
- {
- pos = i;
- break;
- }
- }
-
- // leading whitespace also needs filtering
- needs_filter = needs_filter
- || (numlines > 1)
- || line_is_blank
- || (_at_line_begin() && line.begins_with(' '));
-
- if(pos == npos)
- {
- _line_progressed(line.len);
- ++numlines;
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos >= 0 && pos < m_buf.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf[m_state->pos.offset + pos] == '"');
- _line_progressed(pos + 1); // progress beyond the quote
- pos = m_state->pos.offset - b - 1; // but we stop before it
- break;
- }
-
- _line_ended();
- _scan_line();
- }
-
- if(pos == npos)
- {
- _c4err("reached end of file looking for closing quote");
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos > 0);
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.end() == m_buf.end() || *s.end() == '"');
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.end() >= m_buf.begin() && s.end() <= m_buf.end());
- s = s.sub(0, pos-1);
- }
-
- if(needs_filter)
- {
- csubstr ret = _filter_dquot_scalar(s);
- _c4dbgpf("final scalar: [{}]\"{}\"", ret.len, ret);
- _RYML_CB_ASSERT(m_stack.m_callbacks, ret.len <= s.len || s.empty() || s.trim(' ').empty());
- return ret;
- }
-
- _c4dbgpf("final scalar: \"{}\"", s);
-
- return s;
-}
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_scan_block()
-{
- // nice explanation here: http://yaml-multiline.info/
- csubstr s = m_state->line_contents.rem;
- csubstr trimmed = s.triml(' ');
- if(trimmed.str > s.str)
- {
- _c4dbgp("skipping whitespace");
- _RYML_CB_ASSERT(m_stack.m_callbacks, trimmed.str >= s.str);
- _line_progressed(static_cast<size_t>(trimmed.str - s.str));
- s = trimmed;
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.begins_with('|') || s.begins_with('>'));
-
- _c4dbgpf("scanning block: specs=\"{}\"", s);
-
- // parse the spec
- BlockStyle_e newline = s.begins_with('>') ? BLOCK_FOLD : BLOCK_LITERAL;
- BlockChomp_e chomp = CHOMP_CLIP; // default to clip unless + or - are used
- size_t indentation = npos; // have to find out if no spec is given
- csubstr digits;
- if(s.len > 1)
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.begins_with_any("|>"));
- csubstr t = s.sub(1);
- _c4dbgpf("scanning block: spec is multichar: '{}'", t);
- _RYML_CB_ASSERT(m_stack.m_callbacks, t.len >= 1);
- size_t pos = t.first_of("-+");
- _c4dbgpf("scanning block: spec chomp char at {}", pos);
- if(pos != npos)
- {
- if(t[pos] == '-')
- chomp = CHOMP_STRIP;
- else if(t[pos] == '+')
- chomp = CHOMP_KEEP;
- if(pos == 0)
- t = t.sub(1);
- else
- t = t.first(pos);
- }
- // from here to the end, only digits are considered
- digits = t.left_of(t.first_not_of("0123456789"));
- if( ! digits.empty())
- {
- if( ! c4::atou(digits, &indentation))
- _c4err("parse error: could not read decimal");
- _c4dbgpf("scanning block: indentation specified: {}. add {} from curr state -> {}", indentation, m_state->indref, indentation+m_state->indref);
- indentation += m_state->indref;
- }
- }
-
- // finish the current line
- _line_progressed(s.len);
- _line_ended();
- _scan_line();
-
- _c4dbgpf("scanning block: style={} chomp={} indentation={}", newline==BLOCK_FOLD ? "fold" : "literal", chomp==CHOMP_CLIP ? "clip" : (chomp==CHOMP_STRIP ? "strip" : "keep"), indentation);
-
- // start with a zero-length block, already pointing at the right place
- substr raw_block(m_buf.data() + m_state->pos.offset, size_t(0));// m_state->line_contents.full.sub(0, 0);
- _RYML_CB_ASSERT(m_stack.m_callbacks, raw_block.begin() == m_state->line_contents.full.begin());
-
- // read every full line into a raw block,
- // from which newlines are to be stripped as needed.
- //
- // If no explicit indentation was given, pick it from the first
- // non-empty line. See
- // https://yaml.org/spec/1.2.2/#8111-block-indentation-indicator
- size_t num_lines = 0, first = m_state->pos.line, provisional_indentation = npos;
- LineContents lc;
- while(( ! _finished_file()))
- {
- // peek next line, but do not advance immediately
- lc.reset_with_next_line(m_buf, m_state->pos.offset);
- _c4dbgpf("scanning block: peeking at '{}'", lc.stripped);
- // evaluate termination conditions
- if(indentation != npos)
- {
- // stop when the line is deindented and not empty
- if(lc.indentation < indentation && ( ! lc.rem.trim(" \t\r\n").empty()))
- {
- _c4dbgpf("scanning block: indentation decreased ref={} thisline={}", indentation, lc.indentation);
- break;
- }
- else if(indentation == 0)
- {
- if((lc.rem == "..." || lc.rem.begins_with("... "))
- ||
- (lc.rem == "---" || lc.rem.begins_with("--- ")))
- {
- _c4dbgp("scanning block: stop. indentation=0 and stream ended");
- break;
- }
- }
- }
- else
- {
- _c4dbgpf("scanning block: indentation ref not set. firstnonws={}", lc.stripped.first_not_of(' '));
- if(lc.stripped.first_not_of(' ') != npos) // non-empty line
- {
- _c4dbgpf("scanning block: line not empty. indref={} indprov={} indentation={}", m_state->indref, provisional_indentation, lc.indentation);
- if(provisional_indentation == npos)
- {
- if(lc.indentation < m_state->indref)
- {
- _c4dbgpf("scanning block: block terminated indentation={} < indref={}", lc.indentation, m_state->indref);
- if(raw_block.len == 0)
- {
- _c4dbgp("scanning block: was empty, undo next line");
- _line_ended_undo();
- }
- break;
- }
- else if(lc.indentation == m_state->indref)
- {
- if(has_any(RSEQ|RMAP))
- {
- _c4dbgpf("scanning block: block terminated. reading container and indentation={}==indref={}", lc.indentation, m_state->indref);
- break;
- }
- }
- _c4dbgpf("scanning block: set indentation ref from this line: ref={}", lc.indentation);
- indentation = lc.indentation;
- }
- else
- {
- if(lc.indentation >= provisional_indentation)
- {
- _c4dbgpf("scanning block: set indentation ref from provisional indentation: provisional_ref={}, thisline={}", provisional_indentation, lc.indentation);
- //indentation = provisional_indentation ? provisional_indentation : lc.indentation;
- indentation = lc.indentation;
- }
- else
- {
- break;
- //_c4err("parse error: first non-empty block line should have at least the original indentation");
- }
- }
- }
- else // empty line
- {
- _c4dbgpf("scanning block: line empty or {} spaces. line_indentation={} prov_indentation={}", lc.stripped.len, lc.indentation, provisional_indentation);
- if(provisional_indentation != npos)
- {
- if(lc.stripped.len >= provisional_indentation)
- {
- _c4dbgpf("scanning block: increase provisional_ref {} -> {}", provisional_indentation, lc.stripped.len);
- provisional_indentation = lc.stripped.len;
- }
- #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
- else if(lc.indentation >= provisional_indentation && lc.indentation != npos)
- {
- _c4dbgpf("scanning block: increase provisional_ref {} -> {}", provisional_indentation, lc.indentation);
- provisional_indentation = lc.indentation;
- }
- #endif
- }
- else
- {
- provisional_indentation = lc.indentation ? lc.indentation : has_any(RSEQ|RVAL);
- _c4dbgpf("scanning block: initialize provisional_ref={}", provisional_indentation);
- if(provisional_indentation == npos)
- {
- provisional_indentation = lc.stripped.len ? lc.stripped.len : has_any(RSEQ|RVAL);
- _c4dbgpf("scanning block: initialize provisional_ref={}", provisional_indentation);
- }
- }
- }
- }
- // advance now that we know the folded scalar continues
- m_state->line_contents = lc;
- _c4dbgpf("scanning block: append '{}'", m_state->line_contents.rem);
- raw_block.len += m_state->line_contents.full.len;
- _line_progressed(m_state->line_contents.rem.len);
- _line_ended();
- ++num_lines;
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_state->pos.line == (first + num_lines) || (raw_block.len == 0));
- C4_UNUSED(num_lines);
- C4_UNUSED(first);
-
- if(indentation == npos)
- {
- _c4dbgpf("scanning block: set indentation from provisional: {}", provisional_indentation);
- indentation = provisional_indentation;
- }
-
- if(num_lines)
- _line_ended_undo();
-
- _c4dbgpf("scanning block: raw=~~~{}~~~", raw_block);
-
- // ok! now we strip the newlines and spaces according to the specs
- s = _filter_block_scalar(raw_block, newline, chomp, indentation);
-
- _c4dbgpf("scanning block: final=~~~{}~~~", s);
-
- return s;
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<bool backslash_is_escape, bool keep_trailing_whitespace>
-bool Parser::_filter_nl(substr r, size_t *C4_RESTRICT i, size_t *C4_RESTRICT pos, size_t indentation)
-{
- // a debugging scaffold:
- #if 0
- #define _c4dbgfnl(fmt, ...) _c4dbgpf("filter_nl[{}]: " fmt, *i, __VA_ARGS__)
- #else
- #define _c4dbgfnl(...)
- #endif
-
- const char curr = r[*i];
- bool replaced = false;
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, indentation != npos);
- _RYML_CB_ASSERT(m_stack.m_callbacks, curr == '\n');
-
- _c4dbgfnl("found newline. sofar=[{}]~~~{}~~~", *pos, m_filter_arena.first(*pos));
- size_t ii = *i;
- size_t numnl_following = count_following_newlines(r, &ii, indentation);
- if(numnl_following)
- {
- _c4dbgfnl("{} consecutive (empty) lines {} in the middle. totalws={}", 1+numnl_following, ii < r.len ? "in the middle" : "at the end", ii - *i);
- for(size_t j = 0; j < numnl_following; ++j)
- m_filter_arena.str[(*pos)++] = '\n';
- }
- else
- {
- if(r.first_not_of(" \t", *i+1) != npos)
- {
- m_filter_arena.str[(*pos)++] = ' ';
- _c4dbgfnl("single newline. convert to space. ii={}/{}. sofar=[{}]~~~{}~~~", ii, r.len, *pos, m_filter_arena.first(*pos));
- replaced = true;
- }
- else
- {
- if C4_IF_CONSTEXPR (keep_trailing_whitespace)
- {
- m_filter_arena.str[(*pos)++] = ' ';
- _c4dbgfnl("single newline. convert to space. ii={}/{}. sofar=[{}]~~~{}~~~", ii, r.len, *pos, m_filter_arena.first(*pos));
- replaced = true;
- }
- else
- {
- _c4dbgfnl("last newline, everything else is whitespace. ii={}/{}", ii, r.len);
- *i = r.len;
- }
- }
- if C4_IF_CONSTEXPR (backslash_is_escape)
- {
- if(ii < r.len && r.str[ii] == '\\')
- {
- const char next = ii+1 < r.len ? r.str[ii+1] : '\0';
- if(next == ' ' || next == '\t')
- {
- _c4dbgfnl("extend skip to backslash{}", "");
- ++ii;
- }
- }
- }
- }
- *i = ii - 1; // correct for the loop increment
-
- #undef _c4dbgfnl
-
- return replaced;
-}
-
-
-//-----------------------------------------------------------------------------
-
-template<bool keep_trailing_whitespace>
-void Parser::_filter_ws(substr r, size_t *C4_RESTRICT i, size_t *C4_RESTRICT pos)
-{
- // a debugging scaffold:
- #if 0
- #define _c4dbgfws(fmt, ...) _c4dbgpf("filt_nl[{}]: " fmt, *i, __VA_ARGS__)
- #else
- #define _c4dbgfws(...)
- #endif
-
- const char curr = r[*i];
- _c4dbgfws("found whitespace '{}'", _c4prc(curr));
- _RYML_CB_ASSERT(m_stack.m_callbacks, curr == ' ' || curr == '\t');
-
- size_t first = *i > 0 ? r.first_not_of(" \t", *i) : r.first_not_of(' ', *i);
- if(first != npos)
- {
- if(r[first] == '\n' || r[first] == '\r') // skip trailing whitespace
- {
- _c4dbgfws("whitespace is trailing on line. firstnonws='{}'@{}", _c4prc(r[first]), first);
- *i = first - 1; // correct for the loop increment
- }
- else // a legit whitespace
- {
- m_filter_arena.str[(*pos)++] = curr;
- _c4dbgfws("legit whitespace. sofar=[{}]~~~{}~~~", *pos, m_filter_arena.first(*pos));
- }
- }
- else
- {
- _c4dbgfws("... everything else is trailing whitespace{}", "");
- if C4_IF_CONSTEXPR (keep_trailing_whitespace)
- for(size_t j = *i; j < r.len; ++j)
- m_filter_arena.str[(*pos)++] = r[j];
- *i = r.len;
- }
-
- #undef _c4dbgfws
-}
-
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_filter_plain_scalar(substr s, size_t indentation)
-{
- // a debugging scaffold:
- #if 0
- #define _c4dbgfps(...) _c4dbgpf("filt_plain_scalar" __VA_ARGS__)
- #else
- #define _c4dbgfps(...)
- #endif
-
- _c4dbgfps("before=~~~{}~~~", s);
-
- substr r = s.triml(" \t");
- _grow_filter_arena(r.len);
- size_t pos = 0; // the filtered size
- bool filtered_chars = false;
- for(size_t i = 0; i < r.len; ++i)
- {
- const char curr = r.str[i];
- _c4dbgfps("[{}]: '{}'", i, _c4prc(curr));
- if(curr == ' ' || curr == '\t')
- {
- _filter_ws</*keep_trailing_ws*/false>(r, &i, &pos);
- }
- else if(curr == '\n')
- {
- filtered_chars = _filter_nl</*backslash_is_escape*/false, /*keep_trailing_ws*/false>(r, &i, &pos, indentation);
- }
- else if(curr == '\r') // skip \r --- https://stackoverflow.com/questions/1885900
- {
- ;
- }
- else
- {
- m_filter_arena.str[pos++] = r[i];
- }
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= m_filter_arena.len);
- if(pos < r.len || filtered_chars)
- {
- r = _finish_filter_arena(r, pos);
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len >= r.len);
- _c4dbgfps("#filteredchars={} after=~~~{}~~~", s.len - r.len, r);
-
- #undef _c4dbgfps
- return r;
-}
-
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_filter_squot_scalar(substr s)
-{
- // a debugging scaffold:
- #if 0
- #define _c4dbgfsq(...) _c4dbgpf("filt_squo_scalar")
- #else
- #define _c4dbgfsq(...)
- #endif
-
- // from the YAML spec for double-quoted scalars:
- // https://yaml.org/spec/1.2-old/spec.html#style/flow/single-quoted
-
- _c4dbgfsq(": before=~~~{}~~~", s);
-
- _grow_filter_arena(s.len);
- substr r = s;
- size_t pos = 0; // the filtered size
- bool filtered_chars = false;
- for(size_t i = 0; i < r.len; ++i)
- {
- const char curr = r[i];
- _c4dbgfsq("[{}]: '{}'", i, _c4prc(curr));
- if(curr == ' ' || curr == '\t')
- {
- _filter_ws</*keep_trailing_ws*/true>(r, &i, &pos);
- }
- else if(curr == '\n')
- {
- filtered_chars = _filter_nl</*backslash_is_escape*/false, /*keep_trailing_ws*/true>(r, &i, &pos, /*indentation*/0);
- }
- else if(curr == '\r') // skip \r --- https://stackoverflow.com/questions/1885900
- {
- ;
- }
- else if(curr == '\'')
- {
- char next = i+1 < r.len ? r[i+1] : '\0';
- if(next == '\'')
- {
- _c4dbgfsq("[{}]: two consecutive quotes", i);
- filtered_chars = true;
- m_filter_arena.str[pos++] = '\'';
- ++i;
- }
- }
- else
- {
- m_filter_arena.str[pos++] = curr;
- }
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= m_filter_arena.len);
- if(pos < r.len || filtered_chars)
- {
- r = _finish_filter_arena(r, pos);
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len >= r.len);
- _c4dbgpf(": #filteredchars={} after=~~~{}~~~", s.len - r.len, r);
-
- #undef _c4dbgfsq
- return r;
-}
-
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_filter_dquot_scalar(substr s)
-{
- // a debugging scaffold:
- #if 0
- #define _c4dbgfdq(...) _c4dbgpf("filt_dquo_scalar" __VA_ARGS__)
- #else
- #define _c4dbgfdq(...)
- #endif
-
- _c4dbgfdq(": before=~~~{}~~~", s);
-
- // from the YAML spec for double-quoted scalars:
- // https://yaml.org/spec/1.2-old/spec.html#style/flow/double-quoted
- //
- // All leading and trailing white space characters are excluded
- // from the content. Each continuation line must therefore contain
- // at least one non-space character. Empty lines, if any, are
- // consumed as part of the line folding.
-
- _grow_filter_arena(s.len + 2u * s.count('\\'));
- substr r = s;
- size_t pos = 0; // the filtered size
- bool filtered_chars = false;
- for(size_t i = 0; i < r.len; ++i)
- {
- const char curr = r[i];
- _c4dbgfdq("[{}]: '{}'", i, _c4prc(curr));
- if(curr == ' ' || curr == '\t')
- {
- _filter_ws</*keep_trailing_ws*/true>(r, &i, &pos);
- }
- else if(curr == '\n')
- {
- filtered_chars = _filter_nl</*backslash_is_escape*/true, /*keep_trailing_ws*/true>(r, &i, &pos, /*indentation*/0);
- }
- else if(curr == '\r') // skip \r --- https://stackoverflow.com/questions/1885900
- {
- ;
- }
- else if(curr == '\\')
- {
- char next = i+1 < r.len ? r[i+1] : '\0';
- _c4dbgfdq("[{}]: backslash, next='{}'", i, _c4prc(next));
- filtered_chars = true;
- if(next == '\r')
- {
- if(i+2 < r.len && r[i+2] == '\n')
- {
- ++i; // newline escaped with \ -- skip both (add only one as i is loop-incremented)
- next = '\n';
- _c4dbgfdq("[{}]: was \\r\\n, now next='\\n'", i);
- }
- }
- // remember the loop will also increment i
- if(next == '\n')
- {
- size_t ii = i + 2;
- for( ; ii < r.len; ++ii)
- {
- if(r.str[ii] == ' ' || r.str[ii] == '\t') // skip leading whitespace
- ;
- else
- break;
- }
- i += ii - i - 1;
- }
- else if(next == '"' || next == '/' || next == ' ' || next == '\t') // escapes for json compatibility
- {
- m_filter_arena.str[pos++] = next;
- ++i;
- }
- else if(next == '\r')
- {
- //++i;
- }
- else if(next == 'n')
- {
- m_filter_arena.str[pos++] = '\n';
- ++i;
- }
- else if(next == 'r')
- {
- m_filter_arena.str[pos++] = '\r';
- ++i; // skip
- }
- else if(next == 't')
- {
- m_filter_arena.str[pos++] = '\t';
- ++i;
- }
- else if(next == '\\')
- {
- m_filter_arena.str[pos++] = '\\';
- ++i;
- }
- else if(next == 'x') // UTF8
- {
- if(i + 1u + 2u >= r.len)
- _c4err("\\x requires 2 hex digits");
- uint8_t byteval = {};
- if(!read_hex(r.sub(i + 2u, 2u), &byteval))
- _c4err("failed to read \\x codepoint");
- m_filter_arena.str[pos++] = *(char*)&byteval;
- i += 1u + 2u;
- }
- else if(next == 'u') // UTF16
- {
- if(i + 1u + 4u >= r.len)
- _c4err("\\u requires 4 hex digits");
- char readbuf[8];
- csubstr codepoint = r.sub(i + 2u, 4u);
- uint32_t codepoint_val = {};
- if(!read_hex(codepoint, &codepoint_val))
- _c4err("failed to parse \\u codepoint");
- size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val);
- C4_ASSERT(numbytes <= 4);
- memcpy(m_filter_arena.str + pos, readbuf, numbytes);
- pos += numbytes;
- i += 1u + 4u;
- }
- else if(next == 'U') // UTF32
- {
- if(i + 1u + 8u >= r.len)
- _c4err("\\U requires 8 hex digits");
- char readbuf[8];
- csubstr codepoint = r.sub(i + 2u, 8u);
- uint32_t codepoint_val = {};
- if(!read_hex(codepoint, &codepoint_val))
- _c4err("failed to parse \\U codepoint");
- size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val);
- C4_ASSERT(numbytes <= 4);
- memcpy(m_filter_arena.str + pos, readbuf, numbytes);
- pos += numbytes;
- i += 1u + 8u;
- }
- // https://yaml.org/spec/1.2.2/#rule-c-ns-esc-char
- else if(next == '0')
- {
- m_filter_arena.str[pos++] = '\0';
- ++i;
- }
- else if(next == 'b') // backspace
- {
- m_filter_arena.str[pos++] = '\b';
- ++i;
- }
- else if(next == 'f') // form feed
- {
- m_filter_arena.str[pos++] = '\f';
- ++i;
- }
- else if(next == 'a') // bell character
- {
- m_filter_arena.str[pos++] = '\a';
- ++i;
- }
- else if(next == 'v') // vertical tab
- {
- m_filter_arena.str[pos++] = '\v';
- ++i;
- }
- else if(next == 'e') // escape character
- {
- m_filter_arena.str[pos++] = '\x1b';
- ++i;
- }
- else if(next == '_') // unicode non breaking space \u00a0
- {
- // https://www.compart.com/en/unicode/U+00a0
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x3e, 0xc2);
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x60, 0xa0);
- ++i;
- }
- else if(next == 'N') // unicode next line \u0085
- {
- // https://www.compart.com/en/unicode/U+0085
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x3e, 0xc2);
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x7b, 0x85);
- ++i;
- }
- else if(next == 'L') // unicode line separator \u2028
- {
- // https://www.utf8-chartable.de/unicode-utf8-table.pl?start=8192&number=1024&names=-&utf8=0x&unicodeinhtml=hex
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x1e, 0xe2);
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x80, 0x80);
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x58, 0xa8);
- ++i;
- }
- else if(next == 'P') // unicode paragraph separator \u2029
- {
- // https://www.utf8-chartable.de/unicode-utf8-table.pl?start=8192&number=1024&names=-&utf8=0x&unicodeinhtml=hex
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x1e, 0xe2);
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x80, 0x80);
- m_filter_arena.str[pos++] = _RYML_CHCONST(-0x57, 0xa9);
- ++i;
- }
- _c4dbgfdq("[{}]: backslash...sofar=[{}]~~~{}~~~", i, pos, m_filter_arena.first(pos));
- }
- else
- {
- m_filter_arena.str[pos++] = curr;
- }
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= m_filter_arena.len);
- if(pos < r.len || filtered_chars)
- {
- r = _finish_filter_arena(r, pos);
- }
-
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len >= r.len);
- _c4dbgpf(": #filteredchars={} after=~~~{}~~~", s.len - r.len, r);
-
- #undef _c4dbgfdq
-
- return r;
-}
-
-
-//-----------------------------------------------------------------------------
-bool Parser::_apply_chomp(substr buf, size_t *C4_RESTRICT pos, BlockChomp_e chomp)
-{
- substr trimmed = buf.first(*pos).trimr('\n');
- bool added_newline = false;
- switch(chomp)
- {
- case CHOMP_KEEP:
- if(trimmed.len == *pos)
- {
- _c4dbgpf("chomp=KEEP: add missing newline @{}", *pos);
- //m_filter_arena.str[(*pos)++] = '\n';
- added_newline = true;
- }
- break;
- case CHOMP_CLIP:
- if(trimmed.len == *pos)
- {
- _c4dbgpf("chomp=CLIP: add missing newline @{}", *pos);
- m_filter_arena.str[(*pos)++] = '\n';
- added_newline = true;
- }
- else
- {
- _c4dbgpf("chomp=CLIP: include single trailing newline @{}", trimmed.len+1);
- *pos = trimmed.len + 1;
- }
- break;
- case CHOMP_STRIP:
- _c4dbgpf("chomp=STRIP: strip {}-{}-{} newlines", *pos, trimmed.len, *pos-trimmed.len);
- *pos = trimmed.len;
- break;
- default:
- _c4err("unknown chomp style");
- }
- return added_newline;
-}
-
-
-//-----------------------------------------------------------------------------
-csubstr Parser::_filter_block_scalar(substr s, BlockStyle_e style, BlockChomp_e chomp, size_t indentation)
-{
- // a debugging scaffold:
- #if 0
- #define _c4dbgfbl(fmt, ...) _c4dbgpf("filt_block" fmt, __VA_ARGS__)
- #else
- #define _c4dbgfbl(...)
- #endif
-
- _c4dbgfbl(": indentation={} before=[{}]~~~{}~~~", indentation, s.len, s);
-
- if(chomp != CHOMP_KEEP && s.trim(" \n\r").len == 0u)
- {
- _c4dbgp("filt_block: empty scalar");
- return s.first(0);
- }
-
- substr r = s;
-
- switch(style)
- {
- case BLOCK_LITERAL:
- {
- _c4dbgp("filt_block: style=literal");
- // trim leading whitespace up to indentation
- {
- size_t numws = r.first_not_of(' ');
- if(numws != npos)
- {
- if(numws > indentation)
- r = r.sub(indentation);
- else
- r = r.sub(numws);
- _c4dbgfbl(": after triml=[{}]~~~{}~~~", r.len, r);
- }
- else
- {
- if(chomp != CHOMP_KEEP || r.len == 0)
- {
- _c4dbgfbl(": all spaces {}, return empty", r.len);
- return r.first(0);
- }
- else
- {
- r[0] = '\n';
- return r.first(1);
- }
- }
- }
- _grow_filter_arena(s.len + 2u); // use s.len! because we may need to add a newline at the end, so the leading indentation will allow space for that newline
- size_t pos = 0; // the filtered size
- for(size_t i = 0; i < r.len; ++i)
- {
- const char curr = r.str[i];
- _c4dbgfbl("[{}]='{}' pos={}", i, _c4prc(curr), pos);
- if(curr == '\r')
- continue;
- m_filter_arena.str[pos++] = curr;
- if(curr == '\n')
- {
- _c4dbgfbl("[{}]: found newline", i);
- // skip indentation on the next line
- csubstr rem = r.sub(i+1);
- size_t first = rem.first_not_of(' ');
- if(first != npos)
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, first < rem.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, i+1+first < r.len);
- _c4dbgfbl("[{}]: {} spaces follow before next nonws character @ [{}]='{}'", i, first, i+1+first, rem.str[first]);
- if(first < indentation)
- {
- _c4dbgfbl("[{}]: skip {}<{} spaces from indentation", i, first, indentation);
- i += first;
- }
- else
- {
- _c4dbgfbl("[{}]: skip {} spaces from indentation", i, indentation);
- i += indentation;
- }
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, i+1 <= r.len);
- first = rem.len;
- _c4dbgfbl("[{}]: {} spaces to the end", i, first);
- if(first)
- {
- if(first < indentation)
- {
- _c4dbgfbl("[{}]: skip everything", i);
- --pos;
- break;
- }
- else
- {
- _c4dbgfbl("[{}]: skip {} spaces from indentation", i, indentation);
- i += indentation;
- }
- }
- else if(i+1 == r.len)
- {
- if(chomp == CHOMP_STRIP)
- --pos;
- break;
- }
- }
- }
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, s.len >= pos);
- _c4dbgfbl(": #filteredchars={} after=~~~{}~~~", s.len - r.len, r);
- bool changed = _apply_chomp(m_filter_arena, &pos, chomp);
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= m_filter_arena.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= s.len);
- if(pos < r.len || changed)
- {
- r = _finish_filter_arena(s, pos); // write into s
- }
- break;
- }
- case BLOCK_FOLD:
- {
- _c4dbgp("filt_block: style=fold");
- _grow_filter_arena(r.len + 2);
- size_t pos = 0; // the filtered size
- bool filtered_chars = false;
- bool started = false;
- bool is_indented = false;
- size_t i = r.first_not_of(' ');
- _c4dbgfbl(": first non space at {}", i);
- if(i > indentation)
- {
- is_indented = true;
- i = indentation;
- }
- _c4dbgfbl(": start folding at {}, is_indented={}", i, (int)is_indented);
- auto on_change_indentation = [&](size_t numnl_following, size_t last_newl, size_t first_non_whitespace){
- _c4dbgfbl("[{}]: add 1+{} newlines", i, numnl_following);
- for(size_t j = 0; j < 1 + numnl_following; ++j)
- m_filter_arena.str[pos++] = '\n';
- for(i = last_newl + 1 + indentation; i < first_non_whitespace; ++i)
- {
- if(r.str[i] == '\r')
- continue;
- _c4dbgfbl("[{}]: add '{}'", i, _c4prc(r.str[i]));
- m_filter_arena.str[pos++] = r.str[i];
- }
- --i;
- };
- for( ; i < r.len; ++i)
- {
- const char curr = r.str[i];
- _c4dbgfbl("[{}]='{}'", i, _c4prc(curr));
- if(curr == '\n')
- {
- filtered_chars = true;
- // skip indentation on the next line, and advance over the next non-indented blank lines as well
- size_t first_non_whitespace;
- size_t numnl_following = (size_t)-1;
- while(r[i] == '\n')
- {
- ++numnl_following;
- csubstr rem = r.sub(i+1);
- size_t first = rem.first_not_of(' ');
- _c4dbgfbl("[{}]: found newline. first={} rem.len={}", i, first, rem.len);
- if(first != npos)
- {
- first_non_whitespace = first + i+1;
- while(first_non_whitespace < r.len && r[first_non_whitespace] == '\r')
- ++first_non_whitespace;
- _RYML_CB_ASSERT(m_stack.m_callbacks, first < rem.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, i+1+first < r.len);
- _c4dbgfbl("[{}]: {} spaces follow before next nonws character @ [{}]='{}'", i, first, i+1+first, _c4prc(rem.str[first]));
- if(first < indentation)
- {
- _c4dbgfbl("[{}]: skip {}<{} spaces from indentation", i, first, indentation);
- i += first;
- }
- else
- {
- _c4dbgfbl("[{}]: skip {} spaces from indentation", i, indentation);
- i += indentation;
- if(first > indentation)
- {
- _c4dbgfbl("[{}]: {} further indented than {}, stop newlining", i, first, indentation);
- goto finished_counting_newlines;
- }
- }
- // prepare the next while loop iteration
- // by setting i at the next newline after
- // an empty line
- if(r[first_non_whitespace] == '\n')
- i = first_non_whitespace;
- else
- goto finished_counting_newlines;
- }
- else
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, i+1 <= r.len);
- first = rem.len;
- first_non_whitespace = first + i+1;
- if(first)
- {
- _c4dbgfbl("[{}]: {} spaces to the end", i, first);
- if(first < indentation)
- {
- _c4dbgfbl("[{}]: skip everything", i);
- i += first;
- }
- else
- {
- _c4dbgfbl("[{}]: skip {} spaces from indentation", i, indentation);
- i += indentation;
- if(first > indentation)
- {
- _c4dbgfbl("[{}]: {} spaces missing. not done yet", i, indentation - first);
- goto finished_counting_newlines;
- }
- }
- }
- else // if(i+1 == r.len)
- {
- _c4dbgfbl("[{}]: it's the final newline", i);
- _RYML_CB_ASSERT(m_stack.m_callbacks, i+1 == r.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, rem.len == 0);
- }
- goto end_of_scalar;
- }
- }
- end_of_scalar:
- // Write all the trailing newlines. Since we're
- // at the end no folding is needed, so write every
- // newline (add 1).
- _c4dbgfbl("[{}]: add {} trailing newlines", i, 1+numnl_following);
- for(size_t j = 0; j < 1 + numnl_following; ++j)
- m_filter_arena.str[pos++] = '\n';
- break;
- finished_counting_newlines:
- _c4dbgfbl("[{}]: #newlines={} firstnonws={}", i, numnl_following, first_non_whitespace);
- while(first_non_whitespace < r.len && r[first_non_whitespace] == '\t')
- ++first_non_whitespace;
- _c4dbgfbl("[{}]: #newlines={} firstnonws={}", i, numnl_following, first_non_whitespace);
- _RYML_CB_ASSERT(m_stack.m_callbacks, first_non_whitespace <= r.len);
- size_t last_newl = r.last_of('\n', first_non_whitespace);
- size_t this_indentation = first_non_whitespace - last_newl - 1;
- _c4dbgfbl("[{}]: #newlines={} firstnonws={} lastnewl={} this_indentation={} vs indentation={}", i, numnl_following, first_non_whitespace, last_newl, this_indentation, indentation);
- _RYML_CB_ASSERT(m_stack.m_callbacks, first_non_whitespace >= last_newl + 1);
- _RYML_CB_ASSERT(m_stack.m_callbacks, this_indentation >= indentation);
- if(!started)
- {
- _c4dbgfbl("[{}]: #newlines={}. write all leading newlines", i, numnl_following);
- for(size_t j = 0; j < 1 + numnl_following; ++j)
- m_filter_arena.str[pos++] = '\n';
- if(this_indentation > indentation)
- {
- is_indented = true;
- _c4dbgfbl("[{}]: advance ->{}", i, last_newl + indentation);
- i = last_newl + indentation;
- }
- else
- {
- i = first_non_whitespace - 1;
- _c4dbgfbl("[{}]: advance ->{}", i, first_non_whitespace);
- }
- }
- else if(this_indentation == indentation)
- {
- _c4dbgfbl("[{}]: same indentation", i);
- if(!is_indented)
- {
- if(numnl_following == 0)
- {
- _c4dbgfbl("[{}]: fold!", i);
- m_filter_arena.str[pos++] = ' ';
- }
- else
- {
- _c4dbgfbl("[{}]: add {} newlines", i, 1 + numnl_following);
- for(size_t j = 0; j < numnl_following; ++j)
- m_filter_arena.str[pos++] = '\n';
- }
- i = first_non_whitespace - 1;
- _c4dbgfbl("[{}]: advance {}->{}", i, i, first_non_whitespace);
- }
- else
- {
- _c4dbgfbl("[{}]: back to ref indentation", i);
- is_indented = false;
- on_change_indentation(numnl_following, last_newl, first_non_whitespace);
- _c4dbgfbl("[{}]: advance {}->{}", i, i, first_non_whitespace);
- }
- }
- else
- {
- _c4dbgfbl("[{}]: increased indentation.", i);
- is_indented = true;
- _RYML_CB_ASSERT(m_stack.m_callbacks, this_indentation > indentation);
- on_change_indentation(numnl_following, last_newl, first_non_whitespace);
- _c4dbgfbl("[{}]: advance {}->{}", i, i, first_non_whitespace);
- }
- }
- else if(curr != '\r')
- {
- if(curr != '\t')
- started = true;
- m_filter_arena.str[pos++] = curr;
- }
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= m_filter_arena.len);
- _c4dbgfbl(": #filteredchars={} after=[{}]~~~{}~~~", (int)s.len - (int)pos, pos, m_filter_arena.first(pos));
- bool changed = _apply_chomp(m_filter_arena, &pos, chomp);
- if(pos < r.len || filtered_chars || changed)
- {
- r = _finish_filter_arena(s, pos); // write into s
- }
- }
- break;
- default:
- _c4err("unknown block style");
- }
-
- _c4dbgfbl(": final=[{}]~~~{}~~~", r.len, r);
-
- #undef _c4dbgfbl
-
- return r;
-}
-
-//-----------------------------------------------------------------------------
-size_t Parser::_count_nlines(csubstr src)
-{
- return 1 + src.count('\n');
-}
-
-//-----------------------------------------------------------------------------
-void Parser::_handle_directive(csubstr directive_)
-{
- csubstr directive = directive_;
- if(directive.begins_with("%TAG"))
- {
- TagDirective td;
- _c4dbgpf("%TAG directive: {}", directive_);
- directive = directive.sub(4);
- if(!directive.begins_with(' '))
- _c4err("malformed tag directive: {}", directive_);
- directive = directive.triml(' ');
- size_t pos = directive.find(' ');
- if(pos == npos)
- _c4err("malformed tag directive: {}", directive_);
- td.handle = directive.first(pos);
- directive = directive.sub(td.handle.len).triml(' ');
- pos = directive.find(' ');
- if(pos != npos)
- directive = directive.first(pos);
- td.prefix = directive;
- td.next_node_id = m_tree->size();
- if(m_tree->size() > 0)
- {
- size_t prev = m_tree->size() - 1;
- if(m_tree->is_root(prev) && m_tree->type(prev) != NOTYPE && !m_tree->is_stream(prev))
- ++td.next_node_id;
- }
- _c4dbgpf("%TAG: handle={} prefix={} next_node={}", td.handle, td.prefix, td.next_node_id);
- m_tree->add_tag_directive(td);
- }
- else if(directive.begins_with("%YAML"))
- {
- _c4dbgpf("%YAML directive! ignoring...: {}", directive);
- }
-}
-
-//-----------------------------------------------------------------------------
-void Parser::set_flags(flag_t f, State * s)
-{
-#ifdef RYML_DBG
- char buf1_[64], buf2_[64];
- csubstr buf1 = _prfl(buf1_, f);
- csubstr buf2 = _prfl(buf2_, s->flags);
- _c4dbgpf("state[{}]: setting flags to {}: before={}", s-m_stack.begin(), buf1, buf2);
-#endif
- s->flags = f;
-}
-
-void Parser::add_flags(flag_t on, State * s)
-{
-#ifdef RYML_DBG
- char buf1_[64], buf2_[64], buf3_[64];
- csubstr buf1 = _prfl(buf1_, on);
- csubstr buf2 = _prfl(buf2_, s->flags);
- csubstr buf3 = _prfl(buf3_, s->flags|on);
- _c4dbgpf("state[{}]: adding flags {}: before={} after={}", s-m_stack.begin(), buf1, buf2, buf3);
-#endif
- s->flags |= on;
-}
-
-void Parser::addrem_flags(flag_t on, flag_t off, State * s)
-{
-#ifdef RYML_DBG
- char buf1_[64], buf2_[64], buf3_[64], buf4_[64];
- csubstr buf1 = _prfl(buf1_, on);
- csubstr buf2 = _prfl(buf2_, off);
- csubstr buf3 = _prfl(buf3_, s->flags);
- csubstr buf4 = _prfl(buf4_, ((s->flags|on)&(~off)));
- _c4dbgpf("state[{}]: adding flags {} / removing flags {}: before={} after={}", s-m_stack.begin(), buf1, buf2, buf3, buf4);
-#endif
- s->flags |= on;
- s->flags &= ~off;
-}
-
-void Parser::rem_flags(flag_t off, State * s)
-{
-#ifdef RYML_DBG
- char buf1_[64], buf2_[64], buf3_[64];
- csubstr buf1 = _prfl(buf1_, off);
- csubstr buf2 = _prfl(buf2_, s->flags);
- csubstr buf3 = _prfl(buf3_, s->flags&(~off));
- _c4dbgpf("state[{}]: removing flags {}: before={} after={}", s-m_stack.begin(), buf1, buf2, buf3);
-#endif
- s->flags &= ~off;
-}
-
-//-----------------------------------------------------------------------------
-
-csubstr Parser::_prfl(substr buf, flag_t flags)
-{
- size_t pos = 0;
- bool gotone = false;
-
- #define _prflag(fl) \
- if((flags & fl) == (fl)) \
- { \
- if(gotone) \
- { \
- if(pos + 1 < buf.len) \
- buf[pos] = '|'; \
- ++pos; \
- } \
- csubstr fltxt = #fl; \
- if(pos + fltxt.len <= buf.len) \
- memcpy(buf.str + pos, fltxt.str, fltxt.len); \
- pos += fltxt.len; \
- gotone = true; \
- }
-
- _prflag(RTOP);
- _prflag(RUNK);
- _prflag(RMAP);
- _prflag(RSEQ);
- _prflag(FLOW);
- _prflag(QMRK);
- _prflag(RKEY);
- _prflag(RVAL);
- _prflag(RNXT);
- _prflag(SSCL);
- _prflag(QSCL);
- _prflag(RSET);
- _prflag(NDOC);
- _prflag(RSEQIMAP);
-
- #undef _prflag
-
- RYML_ASSERT(pos <= buf.len);
-
- return buf.first(pos);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-void Parser::_grow_filter_arena(size_t num_characters_needed)
-{
- _c4dbgpf("grow: arena={} numchars={}", m_filter_arena.len, num_characters_needed);
- if(num_characters_needed <= m_filter_arena.len)
- return;
- size_t sz = m_filter_arena.len << 1;
- _c4dbgpf("grow: sz={}", sz);
- sz = num_characters_needed > sz ? num_characters_needed : sz;
- _c4dbgpf("grow: sz={}", sz);
- sz = sz < 128u ? 128u : sz;
- _c4dbgpf("grow: sz={}", sz);
- _RYML_CB_ASSERT(m_stack.m_callbacks, sz >= num_characters_needed);
- _resize_filter_arena(sz);
-}
-
-void Parser::_resize_filter_arena(size_t num_characters)
-{
- if(num_characters > m_filter_arena.len)
- {
- _c4dbgpf("resize: sz={}", num_characters);
- char *prev = m_filter_arena.str;
- if(m_filter_arena.str)
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_filter_arena.len > 0);
- _RYML_CB_FREE(m_stack.m_callbacks, m_filter_arena.str, char, m_filter_arena.len);
- }
- m_filter_arena.str = _RYML_CB_ALLOC_HINT(m_stack.m_callbacks, char, num_characters, prev);
- m_filter_arena.len = num_characters;
- }
-}
-
-substr Parser::_finish_filter_arena(substr dst, size_t pos)
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= m_filter_arena.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, pos <= dst.len);
- memcpy(dst.str, m_filter_arena.str, pos);
- return dst.first(pos);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-csubstr Parser::location_contents(Location const& loc) const
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, loc.offset < m_buf.len);
- return m_buf.sub(loc.offset);
-}
-
-Location Parser::location(ConstNodeRef node) const
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, node.valid());
- return location(*node.tree(), node.id());
-}
-
-Location Parser::location(Tree const& tree, size_t node) const
-{
- // try hard to avoid getting the location from a null string.
- Location loc;
- if(_location_from_node(tree, node, &loc, 0))
- return loc;
- return val_location(m_buf.str);
-}
-
-bool Parser::_location_from_node(Tree const& tree, size_t node, Location *C4_RESTRICT loc, size_t level) const
-{
- if(tree.has_key(node))
- {
- csubstr k = tree.key(node);
- if(C4_LIKELY(k.str != nullptr))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, k.is_sub(m_buf));
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.is_super(k));
- *loc = val_location(k.str);
- return true;
- }
- }
-
- if(tree.has_val(node))
- {
- csubstr v = tree.val(node);
- if(C4_LIKELY(v.str != nullptr))
- {
- _RYML_CB_ASSERT(m_stack.m_callbacks, v.is_sub(m_buf));
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.is_super(v));
- *loc = val_location(v.str);
- return true;
- }
- }
-
- if(tree.is_container(node))
- {
- if(_location_from_cont(tree, node, loc))
- return true;
- }
-
- if(tree.type(node) != NOTYPE && level == 0)
- {
- // try the prev sibling
- {
- const size_t prev = tree.prev_sibling(node);
- if(prev != NONE)
- {
- if(_location_from_node(tree, prev, loc, level+1))
- return true;
- }
- }
- // try the next sibling
- {
- const size_t next = tree.next_sibling(node);
- if(next != NONE)
- {
- if(_location_from_node(tree, next, loc, level+1))
- return true;
- }
- }
- // try the parent
- {
- const size_t parent = tree.parent(node);
- if(parent != NONE)
- {
- if(_location_from_node(tree, parent, loc, level+1))
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool Parser::_location_from_cont(Tree const& tree, size_t node, Location *C4_RESTRICT loc) const
-{
- _RYML_CB_ASSERT(m_stack.m_callbacks, tree.is_container(node));
- if(!tree.is_stream(node))
- {
- const char *node_start = tree._p(node)->m_val.scalar.str; // this was stored in the container
- if(tree.has_children(node))
- {
- size_t child = tree.first_child(node);
- if(tree.has_key(child))
- {
- // when a map starts, the container was set after the key
- csubstr k = tree.key(child);
- if(k.str && node_start > k.str)
- node_start = k.str;
- }
- }
- *loc = val_location(node_start);
- return true;
- }
- else // it's a stream
- {
- *loc = val_location(m_buf.str); // just return the front of the buffer
- }
- return true;
-}
-
-
-Location Parser::val_location(const char *val) const
-{
- if(C4_UNLIKELY(val == nullptr))
- return {m_file, 0, 0, 0};
-
- _RYML_CB_CHECK(m_stack.m_callbacks, m_options.locations());
- // NOTE: if any of these checks fails, the parser needs to be
- // instantiated with locations enabled.
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.str == m_newline_offsets_buf.str);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_buf.len == m_newline_offsets_buf.len);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_options.locations());
- _RYML_CB_ASSERT(m_stack.m_callbacks, !_locations_dirty());
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_newline_offsets != nullptr);
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_newline_offsets_size > 0);
- // NOTE: the pointer needs to belong to the buffer that was used to parse.
- csubstr src = m_buf;
- _RYML_CB_CHECK(m_stack.m_callbacks, val != nullptr || src.str == nullptr);
- _RYML_CB_CHECK(m_stack.m_callbacks, (val >= src.begin() && val <= src.end()) || (src.str == nullptr && val == nullptr));
- // ok. search the first stored newline after the given ptr
- using lineptr_type = size_t const* C4_RESTRICT;
- lineptr_type lineptr = nullptr;
- size_t offset = (size_t)(val - src.begin());
- if(m_newline_offsets_size < 30) // TODO magic number
- {
- // just do a linear search if the size is small.
- for(lineptr_type curr = m_newline_offsets, last = m_newline_offsets + m_newline_offsets_size; curr < last; ++curr)
- {
- if(*curr > offset)
- {
- lineptr = curr;
- break;
- }
- }
- }
- else
- {
- // do a bisection search if the size is not small.
- //
- // We could use std::lower_bound but this is simple enough and
- // spares the include of <algorithm>.
- size_t count = m_newline_offsets_size;
- size_t step;
- lineptr_type it;
- lineptr = m_newline_offsets;
- while(count)
- {
- step = count >> 1;
- it = lineptr + step;
- if(*it < offset)
- {
- lineptr = ++it;
- count -= step + 1;
- }
- else
- {
- count = step;
- }
- }
- }
- _RYML_CB_ASSERT(m_stack.m_callbacks, lineptr >= m_newline_offsets);
- _RYML_CB_ASSERT(m_stack.m_callbacks, lineptr <= m_newline_offsets + m_newline_offsets_size);
- _RYML_CB_ASSERT(m_stack.m_callbacks, *lineptr > offset);
- Location loc;
- loc.name = m_file;
- loc.offset = offset;
- loc.line = (size_t)(lineptr - m_newline_offsets);
- if(lineptr > m_newline_offsets)
- loc.col = (offset - *(lineptr-1) - 1u);
- else
- loc.col = offset;
- return loc;
-}
-
-void Parser::_prepare_locations()
-{
- m_newline_offsets_buf = m_buf;
- size_t numnewlines = 1u + m_buf.count('\n');
- _resize_locations(numnewlines);
- m_newline_offsets_size = 0;
- for(size_t i = 0; i < m_buf.len; i++)
- if(m_buf[i] == '\n')
- m_newline_offsets[m_newline_offsets_size++] = i;
- m_newline_offsets[m_newline_offsets_size++] = m_buf.len;
- _RYML_CB_ASSERT(m_stack.m_callbacks, m_newline_offsets_size == numnewlines);
-}
-
-void Parser::_resize_locations(size_t numnewlines)
-{
- if(numnewlines > m_newline_offsets_capacity)
- {
- if(m_newline_offsets)
- _RYML_CB_FREE(m_stack.m_callbacks, m_newline_offsets, size_t, m_newline_offsets_capacity);
- m_newline_offsets = _RYML_CB_ALLOC_HINT(m_stack.m_callbacks, size_t, numnewlines, m_newline_offsets);
- m_newline_offsets_capacity = numnewlines;
- }
-}
-
-bool Parser::_locations_dirty() const
-{
- return !m_newline_offsets_size;
-}
-
-} // namespace yml
-} // namespace c4
-
-
-#if defined(_MSC_VER)
-# pragma warning(pop)
-#elif defined(__clang__)
-# pragma clang diagnostic pop
-#elif defined(__GNUC__)
-# pragma GCC diagnostic pop
-#endif
diff --git a/thirdparty/ryml/src/c4/yml/parse.hpp b/thirdparty/ryml/src/c4/yml/parse.hpp
deleted file mode 100644
index 659edf7e0..000000000
--- a/thirdparty/ryml/src/c4/yml/parse.hpp
+++ /dev/null
@@ -1,706 +0,0 @@
-#ifndef _C4_YML_PARSE_HPP_
-#define _C4_YML_PARSE_HPP_
-
-#ifndef _C4_YML_TREE_HPP_
-#include "c4/yml/tree.hpp"
-#endif
-
-#ifndef _C4_YML_NODE_HPP_
-#include "c4/yml/node.hpp"
-#endif
-
-#ifndef _C4_YML_DETAIL_STACK_HPP_
-#include "c4/yml/detail/stack.hpp"
-#endif
-
-#include <stdarg.h>
-
-#if defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
-#endif
-
-namespace c4 {
-namespace yml {
-
-struct RYML_EXPORT ParserOptions
-{
-private:
-
- typedef enum : uint32_t {
- LOCATIONS = (1 << 0),
- DEFAULTS = 0,
- } Flags_e;
-
- uint32_t flags = DEFAULTS;
-public:
- ParserOptions() = default;
-
- /** @name source location tracking */
- /** @{ */
-
- /** enable/disable source location tracking */
- ParserOptions& locations(bool enabled)
- {
- if(enabled)
- flags |= LOCATIONS;
- else
- flags &= ~LOCATIONS;
- return *this;
- }
- bool locations() const { return (flags & LOCATIONS) != 0u; }
-
- /** @} */
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-class RYML_EXPORT Parser
-{
-public:
-
- /** @name construction and assignment */
- /** @{ */
-
- Parser(Callbacks const& cb, ParserOptions opts={});
- Parser(ParserOptions opts={}) : Parser(get_callbacks(), opts) {}
- ~Parser();
-
- Parser(Parser &&);
- Parser(Parser const&);
- Parser& operator=(Parser &&);
- Parser& operator=(Parser const&);
-
- /** @} */
-
-public:
-
- /** @name modifiers */
- /** @{ */
-
- /** Reserve a certain capacity for the parsing stack.
- * This should be larger than the expected depth of the parsed
- * YAML tree.
- *
- * The parsing stack is the only (potential) heap memory used by
- * the parser.
- *
- * If the requested capacity is below the default
- * stack size of 16, the memory is used directly in the parser
- * object; otherwise it will be allocated from the heap.
- *
- * @note this reserves memory only for the parser itself; all the
- * allocations for the parsed tree will go through the tree's
- * allocator.
- *
- * @note the tree and the arena can (and should) also be reserved. */
- void reserve_stack(size_t capacity)
- {
- m_stack.reserve(capacity);
- }
-
- /** Reserve a certain capacity for the array used to track node
- * locations in the source buffer. */
- void reserve_locations(size_t num_source_lines)
- {
- _resize_locations(num_source_lines);
- }
-
- /** Reserve a certain capacity for the character arena used to
- * filter scalars. */
- void reserve_filter_arena(size_t num_characters)
- {
- _resize_filter_arena(num_characters);
- }
-
- /** @} */
-
-public:
-
- /** @name getters and modifiers */
- /** @{ */
-
- /** Get the current callbacks in the parser. */
- Callbacks callbacks() const { return m_stack.m_callbacks; }
-
- /** Get the name of the latest file parsed by this object. */
- csubstr filename() const { return m_file; }
-
- /** Get the latest YAML buffer parsed by this object. */
- csubstr source() const { return m_buf; }
-
- size_t stack_capacity() const { return m_stack.capacity(); }
- size_t locations_capacity() const { return m_newline_offsets_capacity; }
- size_t filter_arena_capacity() const { return m_filter_arena.len; }
-
- ParserOptions const& options() const { return m_options; }
-
- /** @} */
-
-public:
-
- /** @name parse_in_place */
- /** @{ */
-
- /** Create a new tree and parse into its root.
- * The tree is created with the callbacks currently in the parser. */
- Tree parse_in_place(csubstr filename, substr src)
- {
- Tree t(callbacks());
- t.reserve(_estimate_capacity(src));
- this->parse_in_place(filename, src, &t, t.root_id());
- return t;
- }
-
- /** Parse into an existing tree, starting at its root node.
- * The callbacks in the tree are kept, and used to allocate
- * the tree members, if any allocation is required. */
- void parse_in_place(csubstr filename, substr src, Tree *t)
- {
- this->parse_in_place(filename, src, t, t->root_id());
- }
-
- /** Parse into an existing node.
- * The callbacks in the tree are kept, and used to allocate
- * the tree members, if any allocation is required. */
- void parse_in_place(csubstr filename, substr src, Tree *t, size_t node_id);
- // ^^^^^^^^^^^^^ this is the workhorse overload; everything else is syntactic candy
-
- /** Parse into an existing node.
- * The callbacks in the tree are kept, and used to allocate
- * the tree members, if any allocation is required. */
- void parse_in_place(csubstr filename, substr src, NodeRef node)
- {
- this->parse_in_place(filename, src, node.tree(), node.id());
- }
-
- RYML_DEPRECATED("use parse_in_place() instead") Tree parse(csubstr filename, substr src) { return parse_in_place(filename, src); }
- RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, Tree *t) { parse_in_place(filename, src, t); }
- RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, Tree *t, size_t node_id) { parse_in_place(filename, src, t, node_id); }
- RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, NodeRef node) { parse_in_place(filename, src, node); }
-
- /** @} */
-
-public:
-
- /** @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
- * will cause a linker error. This is to prevent an accidental
- * copy of the source buffer to the tree's arena, because substr
- * is implicitly convertible to csubstr. If you really intend to parse
- * 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. */
- /** @{ */
-
- // 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."
- 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);
-
- /** Create a new tree and parse into its root.
- * The immutable YAML source is first copied to the tree's arena,
- * and parsed from there.
- * The callbacks in the tree are kept, and used to allocate
- * the tree members, if any allocation is required. */
- Tree parse_in_arena(csubstr filename, csubstr csrc)
- {
- Tree t(callbacks());
- substr src = t.copy_to_arena(csrc);
- t.reserve(_estimate_capacity(csrc));
- this->parse_in_place(filename, src, &t, t.root_id());
- return t;
- }
-
- /** Parse into an existing tree, starting at its root node.
- * The immutable YAML source is first copied to the tree's arena,
- * and parsed from there.
- * The callbacks in the tree are kept, and used to allocate
- * the tree members, if any allocation is required. */
- void parse_in_arena(csubstr filename, csubstr csrc, Tree *t)
- {
- substr src = t->copy_to_arena(csrc);
- this->parse_in_place(filename, src, t, t->root_id());
- }
-
- /** Parse into a specific node in an existing tree.
- * The immutable YAML source is first copied to the tree's arena,
- * and parsed from there.
- * The callbacks in the tree are kept, and used to allocate
- * the tree members, if any allocation is required. */
- void parse_in_arena(csubstr filename, csubstr csrc, Tree *t, size_t node_id)
- {
- substr src = t->copy_to_arena(csrc);
- this->parse_in_place(filename, src, t, node_id);
- }
-
- /** Parse into a specific node in an existing tree.
- * The immutable YAML source is first copied to the tree's arena,
- * and parsed from there.
- * The callbacks in the tree are kept, and used to allocate
- * the tree members, if any allocation is required. */
- void parse_in_arena(csubstr filename, csubstr csrc, NodeRef node)
- {
- substr src = node.tree()->copy_to_arena(csrc);
- this->parse_in_place(filename, src, node.tree(), node.id());
- }
-
- 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); }
-
- /** @} */
-
-public:
-
- /** @name locations */
- /** @{ */
-
- /** Get the location of a node of the last tree to be parsed by this parser. */
- Location location(Tree const& tree, size_t node_id) const;
- /** Get the location of a node of the last tree to be parsed by this parser. */
- Location location(ConstNodeRef node) const;
- /** Get the string starting at a particular location, to the end
- * of the parsed source buffer. */
- csubstr location_contents(Location const& loc) const;
- /** Given a pointer to a buffer position, get the location. @p val
- * must be pointing to somewhere in the source buffer that was
- * last parsed by this object. */
- Location val_location(const char *val) const;
-
- /** @} */
-
-private:
-
- typedef enum {
- BLOCK_LITERAL, //!< keep newlines (|)
- BLOCK_FOLD //!< replace newline with single space (>)
- } BlockStyle_e;
-
- typedef enum {
- CHOMP_CLIP, //!< single newline at end (default)
- CHOMP_STRIP, //!< no newline at end (-)
- CHOMP_KEEP //!< all newlines from end (+)
- } BlockChomp_e;
-
-private:
-
- using flag_t = int;
-
- static size_t _estimate_capacity(csubstr src) { size_t c = _count_nlines(src); c = c >= 16 ? c : 16; return c; }
-
- void _reset();
-
- bool _finished_file() const;
- bool _finished_line() const;
-
- csubstr _peek_next_line(size_t pos=npos) const;
- bool _advance_to_peeked();
- void _scan_line();
-
- csubstr _slurp_doc_scalar();
-
- /**
- * @param [out] quoted
- * Will only be written to if this method returns true.
- * Will be set to true if the scanned scalar was quoted, by '', "", > or |.
- */
- bool _scan_scalar_seq_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
- bool _scan_scalar_map_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
- bool _scan_scalar_seq_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
- bool _scan_scalar_map_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
- bool _scan_scalar_unk(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
-
- csubstr _scan_comment();
- csubstr _scan_squot_scalar();
- csubstr _scan_dquot_scalar();
- csubstr _scan_block();
- substr _scan_plain_scalar_blck(csubstr currscalar, csubstr peeked_line, size_t indentation);
- substr _scan_plain_scalar_flow(csubstr currscalar, csubstr peeked_line);
- substr _scan_complex_key(csubstr currscalar, csubstr peeked_line);
- csubstr _scan_to_next_nonempty_line(size_t indentation);
- csubstr _extend_scanned_scalar(csubstr currscalar);
-
- csubstr _filter_squot_scalar(const substr s);
- csubstr _filter_dquot_scalar(substr s);
- csubstr _filter_plain_scalar(substr s, size_t indentation);
- csubstr _filter_block_scalar(substr s, BlockStyle_e style, BlockChomp_e chomp, size_t indentation);
- template<bool backslash_is_escape, bool keep_trailing_whitespace>
- bool _filter_nl(substr scalar, size_t *C4_RESTRICT pos, size_t *C4_RESTRICT filter_arena_pos, size_t indentation);
- template<bool keep_trailing_whitespace>
- void _filter_ws(substr scalar, size_t *C4_RESTRICT pos, size_t *C4_RESTRICT filter_arena_pos);
- bool _apply_chomp(substr buf, size_t *C4_RESTRICT pos, BlockChomp_e chomp);
-
- void _handle_finished_file();
- void _handle_line();
-
- bool _handle_indentation();
-
- bool _handle_unk();
- bool _handle_map_flow();
- bool _handle_map_blck();
- bool _handle_seq_flow();
- bool _handle_seq_blck();
- bool _handle_top();
- bool _handle_types();
- bool _handle_key_anchors_and_refs();
- bool _handle_val_anchors_and_refs();
- void _move_val_tag_to_key_tag();
- void _move_key_tag_to_val_tag();
- void _move_key_tag2_to_key_tag();
- void _move_val_anchor_to_key_anchor();
- void _move_key_anchor_to_val_anchor();
-
- void _push_level(bool explicit_flow_chars = false);
- void _pop_level();
-
- void _start_unk(bool as_child=true);
-
- void _start_map(bool as_child=true);
- void _start_map_unk(bool as_child);
- void _stop_map();
-
- void _start_seq(bool as_child=true);
- void _stop_seq();
-
- void _start_seqimap();
- void _stop_seqimap();
-
- void _start_doc(bool as_child=true);
- void _stop_doc();
- void _start_new_doc(csubstr rem);
- void _end_stream();
-
- NodeData* _append_val(csubstr val, flag_t quoted=false);
- NodeData* _append_key_val(csubstr val, flag_t val_quoted=false);
- bool _rval_dash_start_or_continue_seq();
-
- void _store_scalar(csubstr s, flag_t is_quoted);
- csubstr _consume_scalar();
- void _move_scalar_from_top();
-
- inline NodeData* _append_val_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); return _append_val({nullptr, size_t(0)}); }
- inline NodeData* _append_key_val_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); return _append_key_val({nullptr, size_t(0)}); }
- inline void _store_scalar_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); _store_scalar({nullptr, size_t(0)}, false); }
-
- void _set_indentation(size_t behind);
- void _save_indentation(size_t behind=0);
- bool _maybe_set_indentation_from_anchor_or_tag();
-
- void _write_key_anchor(size_t node_id);
- void _write_val_anchor(size_t node_id);
-
- void _handle_directive(csubstr directive);
-
- void _skipchars(char c);
- template<size_t N>
- void _skipchars(const char (&chars)[N]);
-
-private:
-
- static size_t _count_nlines(csubstr src);
-
-private:
-
- typedef enum : flag_t {
- RTOP = 0x01 << 0, ///< reading at top level
- RUNK = 0x01 << 1, ///< reading an unknown: must determine whether scalar, map or seq
- RMAP = 0x01 << 2, ///< reading a map
- RSEQ = 0x01 << 3, ///< reading a seq
- FLOW = 0x01 << 4, ///< reading is inside explicit flow chars: [] or {}
- QMRK = 0x01 << 5, ///< reading an explicit key (`? key`)
- RKEY = 0x01 << 6, ///< reading a scalar as key
- RVAL = 0x01 << 7, ///< reading a scalar as val
- RNXT = 0x01 << 8, ///< read next val or keyval
- SSCL = 0x01 << 9, ///< there's a stored scalar
- QSCL = 0x01 << 10, ///< stored scalar was quoted
- RSET = 0x01 << 11, ///< the (implicit) map being read is a !!set. @see https://yaml.org/type/set.html
- NDOC = 0x01 << 12, ///< no document mode. a document has ended and another has not started yet.
- //! reading an implicit map nested in an explicit seq.
- //! eg, {key: [key2: value2, key3: value3]}
- //! is parsed as {key: [{key2: value2}, {key3: value3}]}
- RSEQIMAP = 0x01 << 13,
- } State_e;
-
- struct LineContents
- {
- csubstr full; ///< the full line, including newlines on the right
- csubstr stripped; ///< the stripped line, excluding newlines on the right
- csubstr rem; ///< the stripped line remainder; initially starts at the first non-space character
- size_t indentation; ///< the number of spaces on the beginning of the line
-
- LineContents() : full(), stripped(), rem(), indentation() {}
-
- void reset_with_next_line(csubstr buf, size_t pos);
-
- void reset(csubstr full_, csubstr stripped_)
- {
- full = full_;
- stripped = stripped_;
- rem = stripped_;
- // find the first column where the character is not a space
- indentation = full.first_not_of(' ');
- }
-
- size_t current_col() const
- {
- return current_col(rem);
- }
-
- size_t current_col(csubstr s) const
- {
- RYML_ASSERT(s.str >= full.str);
- RYML_ASSERT(full.is_super(s));
- size_t col = static_cast<size_t>(s.str - full.str);
- return col;
- }
- };
-
- struct State
- {
- flag_t flags;
- size_t level;
- size_t node_id; // don't hold a pointer to the node as it will be relocated during tree resizes
- csubstr scalar;
- size_t scalar_col; // the column where the scalar (or its quotes) begin
-
- Location pos;
- LineContents line_contents;
- size_t indref;
-
- State() : flags(), level(), node_id(), scalar(), scalar_col(), pos(), line_contents(), indref() {}
-
- void reset(const char *file, size_t node_id_)
- {
- flags = RUNK|RTOP;
- level = 0;
- pos.name = to_csubstr(file);
- pos.offset = 0;
- pos.line = 1;
- pos.col = 1;
- node_id = node_id_;
- scalar_col = 0;
- scalar.clear();
- indref = 0;
- }
- };
-
- void _line_progressed(size_t ahead);
- void _line_ended();
- void _line_ended_undo();
-
- void _prepare_pop()
- {
- RYML_ASSERT(m_stack.size() > 1);
- State const& curr = m_stack.top();
- State & next = m_stack.top(1);
- next.pos = curr.pos;
- next.line_contents = curr.line_contents;
- next.scalar = curr.scalar;
- }
-
- inline bool _at_line_begin() const
- {
- return m_state->line_contents.rem.begin() == m_state->line_contents.full.begin();
- }
- inline bool _at_line_end() const
- {
- csubstr r = m_state->line_contents.rem;
- return r.empty() || r.begins_with(' ', r.len);
- }
- inline bool _token_is_from_this_line(csubstr token) const
- {
- return token.is_sub(m_state->line_contents.full);
- }
-
- inline NodeData * node(State const* s) const { return m_tree->get(s->node_id); }
- inline NodeData * node(State const& s) const { return m_tree->get(s .node_id); }
- inline NodeData * node(size_t node_id) const { return m_tree->get( node_id); }
-
- inline bool has_all(flag_t f) const { return (m_state->flags & f) == f; }
- inline bool has_any(flag_t f) const { return (m_state->flags & f) != 0; }
- inline bool has_none(flag_t f) const { return (m_state->flags & f) == 0; }
-
- static inline bool has_all(flag_t f, State const* s) { return (s->flags & f) == f; }
- static inline bool has_any(flag_t f, State const* s) { return (s->flags & f) != 0; }
- static inline bool has_none(flag_t f, State const* s) { return (s->flags & f) == 0; }
-
- inline void set_flags(flag_t f) { set_flags(f, m_state); }
- inline void add_flags(flag_t on) { add_flags(on, m_state); }
- inline void addrem_flags(flag_t on, flag_t off) { addrem_flags(on, off, m_state); }
- inline void rem_flags(flag_t off) { rem_flags(off, m_state); }
-
- void set_flags(flag_t f, State * s);
- void add_flags(flag_t on, State * s);
- void addrem_flags(flag_t on, flag_t off, State * s);
- void rem_flags(flag_t off, State * s);
-
- void _resize_filter_arena(size_t num_characters);
- void _grow_filter_arena(size_t num_characters);
- substr _finish_filter_arena(substr dst, size_t pos);
-
- void _prepare_locations();
- void _resize_locations(size_t sz);
- bool _locations_dirty() const;
-
- bool _location_from_cont(Tree const& tree, size_t node, Location *C4_RESTRICT loc) const;
- bool _location_from_node(Tree const& tree, size_t node, Location *C4_RESTRICT loc, size_t level) const;
-
-private:
-
- void _free();
- void _clr();
- void _cp(Parser const* that);
- void _mv(Parser *that);
-
-#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 DumpFn> void _fmt_msg(DumpFn &&dumpfn) const;
- static csubstr _prfl(substr buf, flag_t v);
-
-private:
-
- ParserOptions m_options;
-
- csubstr m_file;
- substr m_buf;
-
- size_t m_root_id;
- Tree * m_tree;
-
- detail::stack<State> m_stack;
- State * m_state;
-
- size_t m_key_tag_indentation;
- size_t m_key_tag2_indentation;
- csubstr m_key_tag;
- csubstr m_key_tag2;
- size_t m_val_tag_indentation;
- csubstr m_val_tag;
-
- bool m_key_anchor_was_before;
- size_t m_key_anchor_indentation;
- csubstr m_key_anchor;
- size_t m_val_anchor_indentation;
- csubstr m_val_anchor;
-
- substr m_filter_arena;
-
- size_t *m_newline_offsets;
- size_t m_newline_offsets_size;
- size_t m_newline_offsets_capacity;
- csubstr m_newline_offsets_buf;
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** @name parse_in_place
- *
- * @desc parse a mutable YAML source 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() */
-/** @{ */
-
-inline Tree parse_in_place( substr yaml ) { Parser np; return np.parse_in_place({} , yaml); } //!< parse in-situ a modifiable YAML source buffer.
-inline Tree parse_in_place(csubstr filename, substr yaml ) { Parser np; return np.parse_in_place(filename, yaml); } //!< parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
-inline void parse_in_place( substr yaml, Tree *t ) { Parser np; np.parse_in_place({} , yaml, t); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
-inline void parse_in_place(csubstr filename, substr yaml, Tree *t ) { Parser np; np.parse_in_place(filename, yaml, t); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
-inline void parse_in_place( substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place({} , yaml, t, node_id); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
-inline void parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
-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.
-
-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); }
-RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, Tree *t ) { Parser np; np.parse_in_place(filename, yaml, t); }
-RYML_DEPRECATED("use parse_in_place() instead") inline void parse( substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place({} , yaml, t, node_id); }
-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); }
-
-/** @} */
-
-
-//-----------------------------------------------------------------------------
-
-/** @name parse_in_arena
- * @desc parse a read-only YAML source buffer, copying it first to the tree's 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().
- *
- * @note overloads receiving a substr YAML buffer are intentionally
- * left undefined, such that calling parse_in_arena() with a substr
- * will cause a linker error. This is to prevent an accidental
- * copy of the source buffer to the tree's arena, because substr
- * is implicitly convertible to csubstr. If you really intend to parse
- * 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. */
-/** @{ */
-
-/* READ THE NOTE ABOVE! */
-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 );
-RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t );
-RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t, size_t node_id);
-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 );
-
-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.
-inline void parse_in_arena( 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.
-inline void parse_in_arena(csubstr filename, csubstr yaml, Tree *t ) { Parser np; np.parse_in_arena(filename, yaml, t); } //!< 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.
-inline void parse_in_arena( csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena({} , yaml, t, node_id); } //!< 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, 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.
-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.
-
-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.
-RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, Tree *t ) { Parser np; np.parse_in_arena(filename, yaml, t); } //!< 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, Tree *t, size_t node_id) { Parser np; np.parse_in_arena({} , yaml, t, node_id); } //!< 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, 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.
-
-/** @} */
-
-} // namespace yml
-} // namespace c4
-
-#if defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-#endif /* _C4_YML_PARSE_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/preprocess.cpp b/thirdparty/ryml/src/c4/yml/preprocess.cpp
deleted file mode 100644
index 2e92dce14..000000000
--- a/thirdparty/ryml/src/c4/yml/preprocess.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "c4/yml/preprocess.hpp"
-#include "c4/yml/detail/parser_dbg.hpp"
-
-/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
-
-namespace c4 {
-namespace yml {
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-namespace {
-C4_ALWAYS_INLINE bool _is_idchar(char c)
-{
- return (c >= 'a' && c <= 'z')
- || (c >= 'A' && c <= 'Z')
- || (c >= '0' && c <= '9')
- || (c == '_' || c == '-' || c == '~' || c == '$');
-}
-
-typedef enum { kReadPending = 0, kKeyPending = 1, kValPending = 2 } _ppstate;
-C4_ALWAYS_INLINE _ppstate _next(_ppstate s)
-{
- int n = (int)s + 1;
- return (_ppstate)(n <= (int)kValPending ? n : 0);
-}
-} // empty namespace
-
-
-//-----------------------------------------------------------------------------
-
-size_t preprocess_rxmap(csubstr s, substr buf)
-{
- detail::_SubstrWriter writer(buf);
- _ppstate state = kReadPending;
- size_t last = 0;
-
- if(s.begins_with('{'))
- {
- RYML_CHECK(s.ends_with('}'));
- s = s.offs(1, 1);
- }
-
- writer.append('{');
-
- for(size_t i = 0; i < s.len; ++i)
- {
- const char curr = s[i];
- const char next = i+1 < s.len ? s[i+1] : '\0';
-
- if(curr == '\'' || curr == '"')
- {
- csubstr ss = s.sub(i).pair_range_esc(curr, '\\');
- i += static_cast<size_t>(ss.end() - (s.str + i));
- state = _next(state);
- }
- else if(state == kReadPending && _is_idchar(curr))
- {
- state = _next(state);
- }
-
- switch(state)
- {
- case kKeyPending:
- {
- if(curr == ':' && next == ' ')
- {
- state = _next(state);
- }
- else if(curr == ',' && next == ' ')
- {
- writer.append(s.range(last, i));
- writer.append(": 1, ");
- last = i + 2;
- }
- break;
- }
- case kValPending:
- {
- if(curr == '[' || curr == '{' || curr == '(')
- {
- csubstr ss = s.sub(i).pair_range_nested(curr, '\\');
- i += static_cast<size_t>(ss.end() - (s.str + i));
- state = _next(state);
- }
- else if(curr == ',' && next == ' ')
- {
- state = _next(state);
- }
- break;
- }
- default:
- // nothing to do
- break;
- }
- }
-
- writer.append(s.sub(last));
- if(state == kKeyPending)
- writer.append(": 1");
- writer.append('}');
-
- return writer.pos;
-}
-
-
-} // namespace yml
-} // namespace c4
diff --git a/thirdparty/ryml/src/c4/yml/preprocess.hpp b/thirdparty/ryml/src/c4/yml/preprocess.hpp
deleted file mode 100644
index def066389..000000000
--- a/thirdparty/ryml/src/c4/yml/preprocess.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef _C4_YML_PREPROCESS_HPP_
-#define _C4_YML_PREPROCESS_HPP_
-
-/** @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
-#include <c4/substr.hpp>
-
-
-namespace c4 {
-namespace yml {
-
-namespace detail {
-using Preprocessor = size_t(csubstr, substr);
-template<Preprocessor PP, class CharContainer>
-substr preprocess_into_container(csubstr input, CharContainer *out)
-{
- // try to write once. the preprocessor will stop writing at the end of
- // the container, but will process all the input to determine the
- // required container size.
- size_t sz = PP(input, to_substr(*out));
- // if the container size is not enough, resize, and run again in the
- // resized container
- if(sz > out->size())
- {
- out->resize(sz);
- sz = PP(input, to_substr(*out));
- }
- return to_substr(*out).first(sz);
-}
-} // namespace detail
-
-
-//-----------------------------------------------------------------------------
-
-/** @name preprocess_rxmap
- * Convert flow-type relaxed maps (with implicit bools) into strict YAML
- * flow map.
- *
- * @code{.yaml}
- * {a, b, c, d: [e, f], g: {a, b}}
- * # is converted into this:
- * {a: 1, b: 1, c: 1, d: [e, f], g: {a, b}}
- * @endcode
-
- * @note this is NOT recursive - conversion happens only in the top-level map
- * @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.
- *
- * @return the number of characters required for output
- */
-RYML_EXPORT size_t preprocess_rxmap(csubstr rxmap, substr buf);
-
-
-/** Write into an existing container. It is resized to contained the output.
- * @return a substr of the container
- * @overload preprocess_rxmap */
-template<class CharContainer>
-substr preprocess_rxmap(csubstr rxmap, CharContainer *out)
-{
- return detail::preprocess_into_container<preprocess_rxmap>(rxmap, out);
-}
-
-
-/** Create a container with the result.
- * @overload preprocess_rxmap */
-template<class CharContainer>
-CharContainer preprocess_rxmap(csubstr rxmap)
-{
- CharContainer out;
- preprocess_rxmap(rxmap, &out);
- return out;
-}
-
-//@}
-
-} // namespace yml
-} // namespace c4
-
-#endif /* _C4_YML_PREPROCESS_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/std/map.hpp b/thirdparty/ryml/src/c4/yml/std/map.hpp
deleted file mode 100644
index fc48dc5e6..000000000
--- a/thirdparty/ryml/src/c4/yml/std/map.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _C4_YML_STD_MAP_HPP_
-#define _C4_YML_STD_MAP_HPP_
-
-/** @file map.hpp write/read std::map to/from a YAML tree. */
-
-#include "c4/yml/node.hpp"
-#include <map>
-
-namespace c4 {
-namespace yml {
-
-// std::map requires child nodes in the data
-// tree hierarchy (a MAP node in ryml parlance).
-// So it should be serialized via write()/read().
-
-template<class K, class V, class Less, class Alloc>
-void write(c4::yml::NodeRef *n, std::map<K, V, Less, Alloc> const& m)
-{
- *n |= c4::yml::MAP;
- for(auto const& C4_RESTRICT p : m)
- {
- auto ch = n->append_child();
- ch << c4::yml::key(p.first);
- ch << p.second;
- }
-}
-
-template<class K, class V, class Less, class Alloc>
-bool read(c4::yml::ConstNodeRef const& n, std::map<K, V, Less, Alloc> * m)
-{
- K k{};
- V v{};
- for(auto const& C4_RESTRICT ch : n)
- {
- ch >> c4::yml::key(k);
- ch >> v;
- m->emplace(std::make_pair(std::move(k), std::move(v)));
- }
- return true;
-}
-
-} // namespace yml
-} // namespace c4
-
-#endif // _C4_YML_STD_MAP_HPP_
diff --git a/thirdparty/ryml/src/c4/yml/std/std.hpp b/thirdparty/ryml/src/c4/yml/std/std.hpp
deleted file mode 100644
index 08e80d155..000000000
--- a/thirdparty/ryml/src/c4/yml/std/std.hpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _C4_YML_STD_STD_HPP_
-#define _C4_YML_STD_STD_HPP_
-
-#include "c4/yml/std/string.hpp"
-#include "c4/yml/std/vector.hpp"
-#include "c4/yml/std/map.hpp"
-
-#endif // _C4_YML_STD_STD_HPP_
diff --git a/thirdparty/ryml/src/c4/yml/std/string.hpp b/thirdparty/ryml/src/c4/yml/std/string.hpp
deleted file mode 100644
index e3318f91c..000000000
--- a/thirdparty/ryml/src/c4/yml/std/string.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef C4_YML_STD_STRING_HPP_
-#define C4_YML_STD_STRING_HPP_
-
-/** @file string.hpp substring conversions for/from std::string */
-
-// everything we need is implemented here:
-#include <c4/std/string.hpp>
-
-#endif // C4_YML_STD_STRING_HPP_
diff --git a/thirdparty/ryml/src/c4/yml/std/vector.hpp b/thirdparty/ryml/src/c4/yml/std/vector.hpp
deleted file mode 100644
index 1b6a4610a..000000000
--- a/thirdparty/ryml/src/c4/yml/std/vector.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _C4_YML_STD_VECTOR_HPP_
-#define _C4_YML_STD_VECTOR_HPP_
-
-#include "c4/yml/node.hpp"
-#include <c4/std/vector.hpp>
-#include <vector>
-
-namespace c4 {
-namespace yml {
-
-// vector is a sequence-like type, and it requires child nodes
-// in the data tree hierarchy (a SEQ node in ryml parlance).
-// So it should be serialized via write()/read().
-
-
-template<class V, class Alloc>
-void write(c4::yml::NodeRef *n, std::vector<V, Alloc> const& vec)
-{
- *n |= c4::yml::SEQ;
- for(auto const& v : vec)
- n->append_child() << v;
-}
-
-template<class V, class Alloc>
-bool read(c4::yml::ConstNodeRef const& n, std::vector<V, Alloc> *vec)
-{
- vec->resize(n.num_children());
- size_t pos = 0;
- for(auto const ch : n)
- ch >> (*vec)[pos++];
- return true;
-}
-
-/** specialization: std::vector<bool> uses std::vector<bool>::reference as
- * the return value of its operator[]. */
-template<class Alloc>
-bool read(c4::yml::ConstNodeRef const& n, std::vector<bool, Alloc> *vec)
-{
- vec->resize(n.num_children());
- size_t pos = 0;
- bool tmp;
- for(auto const ch : n)
- {
- ch >> tmp;
- (*vec)[pos++] = tmp;
- }
- return true;
-}
-
-} // namespace yml
-} // namespace c4
-
-#endif // _C4_YML_STD_VECTOR_HPP_
diff --git a/thirdparty/ryml/src/c4/yml/tree.cpp b/thirdparty/ryml/src/c4/yml/tree.cpp
deleted file mode 100644
index b16ff8f5d..000000000
--- a/thirdparty/ryml/src/c4/yml/tree.cpp
+++ /dev/null
@@ -1,2183 +0,0 @@
-#include "c4/yml/tree.hpp"
-#include "c4/yml/detail/parser_dbg.hpp"
-#include "c4/yml/node.hpp"
-#include "c4/yml/detail/stack.hpp"
-
-
-C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wtype-limits")
-C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296/*expression is always 'boolean_value'*/)
-
-namespace c4 {
-namespace yml {
-
-
-csubstr normalize_tag(csubstr tag)
-{
- YamlTag_e t = to_tag(tag);
- if(t != TAG_NONE)
- return from_tag(t);
- if(tag.begins_with("!<"))
- tag = tag.sub(1);
- if(tag.begins_with("<!"))
- return tag;
- return tag;
-}
-
-csubstr normalize_tag_long(csubstr tag)
-{
- YamlTag_e t = to_tag(tag);
- if(t != TAG_NONE)
- return from_tag_long(t);
- if(tag.begins_with("!<"))
- tag = tag.sub(1);
- if(tag.begins_with("<!"))
- return tag;
- return tag;
-}
-
-YamlTag_e to_tag(csubstr tag)
-{
- if(tag.begins_with("!<"))
- tag = tag.sub(1);
- if(tag.begins_with("!!"))
- tag = tag.sub(2);
- else if(tag.begins_with('!'))
- return TAG_NONE;
- else if(tag.begins_with("tag:yaml.org,2002:"))
- {
- RYML_ASSERT(csubstr("tag:yaml.org,2002:").len == 18);
- tag = tag.sub(18);
- }
- else if(tag.begins_with("<tag:yaml.org,2002:"))
- {
- RYML_ASSERT(csubstr("<tag:yaml.org,2002:").len == 19);
- tag = tag.sub(19);
- if(!tag.len)
- return TAG_NONE;
- tag = tag.offs(0, 1);
- }
-
- if(tag == "map")
- return TAG_MAP;
- else if(tag == "omap")
- return TAG_OMAP;
- else if(tag == "pairs")
- return TAG_PAIRS;
- else if(tag == "set")
- return TAG_SET;
- else if(tag == "seq")
- return TAG_SEQ;
- else if(tag == "binary")
- return TAG_BINARY;
- else if(tag == "bool")
- return TAG_BOOL;
- else if(tag == "float")
- return TAG_FLOAT;
- else if(tag == "int")
- return TAG_INT;
- else if(tag == "merge")
- return TAG_MERGE;
- else if(tag == "null")
- return TAG_NULL;
- else if(tag == "str")
- return TAG_STR;
- else if(tag == "timestamp")
- return TAG_TIMESTAMP;
- else if(tag == "value")
- return TAG_VALUE;
-
- return TAG_NONE;
-}
-
-csubstr from_tag_long(YamlTag_e tag)
-{
- switch(tag)
- {
- case TAG_MAP:
- return {"<tag:yaml.org,2002:map>"};
- case TAG_OMAP:
- return {"<tag:yaml.org,2002:omap>"};
- case TAG_PAIRS:
- return {"<tag:yaml.org,2002:pairs>"};
- case TAG_SET:
- return {"<tag:yaml.org,2002:set>"};
- case TAG_SEQ:
- return {"<tag:yaml.org,2002:seq>"};
- case TAG_BINARY:
- return {"<tag:yaml.org,2002:binary>"};
- case TAG_BOOL:
- return {"<tag:yaml.org,2002:bool>"};
- case TAG_FLOAT:
- return {"<tag:yaml.org,2002:float>"};
- case TAG_INT:
- return {"<tag:yaml.org,2002:int>"};
- case TAG_MERGE:
- return {"<tag:yaml.org,2002:merge>"};
- case TAG_NULL:
- return {"<tag:yaml.org,2002:null>"};
- case TAG_STR:
- return {"<tag:yaml.org,2002:str>"};
- case TAG_TIMESTAMP:
- return {"<tag:yaml.org,2002:timestamp>"};
- case TAG_VALUE:
- return {"<tag:yaml.org,2002:value>"};
- case TAG_YAML:
- return {"<tag:yaml.org,2002:yaml>"};
- case TAG_NONE:
- return {""};
- }
- return {""};
-}
-
-csubstr from_tag(YamlTag_e tag)
-{
- switch(tag)
- {
- case TAG_MAP:
- return {"!!map"};
- case TAG_OMAP:
- return {"!!omap"};
- case TAG_PAIRS:
- return {"!!pairs"};
- case TAG_SET:
- return {"!!set"};
- case TAG_SEQ:
- return {"!!seq"};
- case TAG_BINARY:
- return {"!!binary"};
- case TAG_BOOL:
- return {"!!bool"};
- case TAG_FLOAT:
- return {"!!float"};
- case TAG_INT:
- return {"!!int"};
- case TAG_MERGE:
- return {"!!merge"};
- case TAG_NULL:
- return {"!!null"};
- case TAG_STR:
- return {"!!str"};
- case TAG_TIMESTAMP:
- return {"!!timestamp"};
- case TAG_VALUE:
- return {"!!value"};
- case TAG_YAML:
- return {"!!yaml"};
- case TAG_NONE:
- return {""};
- }
- return {""};
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-const char* NodeType::type_str(NodeType_e ty)
-{
- switch(ty & _TYMASK)
- {
- case KEYVAL:
- return "KEYVAL";
- case KEY:
- return "KEY";
- case VAL:
- return "VAL";
- case MAP:
- return "MAP";
- case SEQ:
- return "SEQ";
- case KEYMAP:
- return "KEYMAP";
- case KEYSEQ:
- return "KEYSEQ";
- case DOCSEQ:
- return "DOCSEQ";
- case DOCMAP:
- return "DOCMAP";
- case DOCVAL:
- return "DOCVAL";
- case DOC:
- return "DOC";
- case STREAM:
- return "STREAM";
- case NOTYPE:
- return "NOTYPE";
- default:
- if((ty & KEYVAL) == KEYVAL)
- return "KEYVAL***";
- if((ty & KEYMAP) == KEYMAP)
- return "KEYMAP***";
- if((ty & KEYSEQ) == KEYSEQ)
- return "KEYSEQ***";
- if((ty & DOCSEQ) == DOCSEQ)
- return "DOCSEQ***";
- if((ty & DOCMAP) == DOCMAP)
- return "DOCMAP***";
- if((ty & DOCVAL) == DOCVAL)
- return "DOCVAL***";
- if(ty & KEY)
- return "KEY***";
- if(ty & VAL)
- return "VAL***";
- if(ty & MAP)
- return "MAP***";
- if(ty & SEQ)
- return "SEQ***";
- if(ty & DOC)
- return "DOC***";
- return "(unk)";
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-NodeRef Tree::rootref()
-{
- return NodeRef(this, root_id());
-}
-ConstNodeRef Tree::rootref() const
-{
- return ConstNodeRef(this, root_id());
-}
-
-ConstNodeRef Tree::crootref()
-{
- return ConstNodeRef(this, root_id());
-}
-ConstNodeRef Tree::crootref() const
-{
- return ConstNodeRef(this, root_id());
-}
-
-NodeRef Tree::ref(size_t id)
-{
- _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);
- return NodeRef(this, id);
-}
-ConstNodeRef Tree::ref(size_t id) const
-{
- _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);
- return ConstNodeRef(this, id);
-}
-
-ConstNodeRef Tree::cref(size_t id)
-{
- _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);
- return ConstNodeRef(this, id);
-}
-ConstNodeRef Tree::cref(size_t id) const
-{
- _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);
- return ConstNodeRef(this, id);
-}
-
-NodeRef Tree::operator[] (csubstr key)
-{
- return rootref()[key];
-}
-ConstNodeRef Tree::operator[] (csubstr key) const
-{
- return rootref()[key];
-}
-
-NodeRef Tree::operator[] (size_t i)
-{
- return rootref()[i];
-}
-ConstNodeRef Tree::operator[] (size_t i) const
-{
- return rootref()[i];
-}
-
-NodeRef Tree::docref(size_t i)
-{
- return ref(doc(i));
-}
-ConstNodeRef Tree::docref(size_t i) const
-{
- return cref(doc(i));
-}
-
-
-//-----------------------------------------------------------------------------
-Tree::Tree(Callbacks const& cb)
- : m_buf(nullptr)
- , m_cap(0)
- , m_size(0)
- , m_free_head(NONE)
- , m_free_tail(NONE)
- , m_arena()
- , m_arena_pos(0)
- , m_callbacks(cb)
-{
-}
-
-Tree::Tree(size_t node_capacity, size_t arena_capacity, Callbacks const& cb)
- : Tree(cb)
-{
- reserve(node_capacity);
- reserve_arena(arena_capacity);
-}
-
-Tree::~Tree()
-{
- _free();
-}
-
-
-Tree::Tree(Tree const& that) noexcept : Tree(that.m_callbacks)
-{
- _copy(that);
-}
-
-Tree& Tree::operator= (Tree const& that) noexcept
-{
- _free();
- m_callbacks = that.m_callbacks;
- _copy(that);
- return *this;
-}
-
-Tree::Tree(Tree && that) noexcept : Tree(that.m_callbacks)
-{
- _move(that);
-}
-
-Tree& Tree::operator= (Tree && that) noexcept
-{
- _free();
- m_callbacks = that.m_callbacks;
- _move(that);
- return *this;
-}
-
-void Tree::_free()
-{
- if(m_buf)
- {
- _RYML_CB_ASSERT(m_callbacks, m_cap > 0);
- _RYML_CB_FREE(m_callbacks, m_buf, NodeData, m_cap);
- }
- if(m_arena.str)
- {
- _RYML_CB_ASSERT(m_callbacks, m_arena.len > 0);
- _RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);
- }
- _clear();
-}
-
-
-C4_SUPPRESS_WARNING_GCC_PUSH
-#if defined(__GNUC__) && __GNUC__>= 8
- C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wclass-memaccess") // error: ‘void* memset(void*, int, size_t)’ clearing an object of type ‘class c4::yml::Tree’ with no trivial copy-assignment; use assignment or value-initialization instead
-#endif
-
-void Tree::_clear()
-{
- m_buf = nullptr;
- m_cap = 0;
- m_size = 0;
- m_free_head = 0;
- m_free_tail = 0;
- m_arena = {};
- m_arena_pos = 0;
- for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
- m_tag_directives[i] = {};
-}
-
-void Tree::_copy(Tree const& that)
-{
- _RYML_CB_ASSERT(m_callbacks, m_buf == nullptr);
- _RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr);
- _RYML_CB_ASSERT(m_callbacks, m_arena.len == 0);
- m_buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, that.m_cap, that.m_buf);
- memcpy(m_buf, that.m_buf, that.m_cap * sizeof(NodeData));
- m_cap = that.m_cap;
- m_size = that.m_size;
- m_free_head = that.m_free_head;
- m_free_tail = that.m_free_tail;
- m_arena_pos = that.m_arena_pos;
- m_arena = that.m_arena;
- if(that.m_arena.str)
- {
- _RYML_CB_ASSERT(m_callbacks, that.m_arena.len > 0);
- substr arena;
- arena.str = _RYML_CB_ALLOC_HINT(m_callbacks, char, that.m_arena.len, that.m_arena.str);
- arena.len = that.m_arena.len;
- _relocate(arena); // does a memcpy of the arena and updates nodes using the old arena
- m_arena = arena;
- }
- for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
- m_tag_directives[i] = that.m_tag_directives[i];
-}
-
-void Tree::_move(Tree & that)
-{
- _RYML_CB_ASSERT(m_callbacks, m_buf == nullptr);
- _RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr);
- _RYML_CB_ASSERT(m_callbacks, m_arena.len == 0);
- m_buf = that.m_buf;
- m_cap = that.m_cap;
- m_size = that.m_size;
- m_free_head = that.m_free_head;
- m_free_tail = that.m_free_tail;
- m_arena = that.m_arena;
- m_arena_pos = that.m_arena_pos;
- for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
- m_tag_directives[i] = that.m_tag_directives[i];
- that._clear();
-}
-
-void Tree::_relocate(substr next_arena)
-{
- _RYML_CB_ASSERT(m_callbacks, next_arena.not_empty());
- _RYML_CB_ASSERT(m_callbacks, next_arena.len >= m_arena.len);
- memcpy(next_arena.str, m_arena.str, m_arena_pos);
- for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n)
- {
- if(in_arena(n->m_key.scalar))
- n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
- if(in_arena(n->m_key.tag))
- n->m_key.tag = _relocated(n->m_key.tag, next_arena);
- if(in_arena(n->m_key.anchor))
- n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
- if(in_arena(n->m_val.scalar))
- n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
- if(in_arena(n->m_val.tag))
- n->m_val.tag = _relocated(n->m_val.tag, next_arena);
- if(in_arena(n->m_val.anchor))
- n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
- }
- for(TagDirective &C4_RESTRICT td : m_tag_directives)
- {
- if(in_arena(td.prefix))
- td.prefix = _relocated(td.prefix, next_arena);
- if(in_arena(td.handle))
- td.handle = _relocated(td.handle, next_arena);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-void Tree::reserve(size_t cap)
-{
- if(cap > m_cap)
- {
- NodeData *buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, cap, m_buf);
- if(m_buf)
- {
- memcpy(buf, m_buf, m_cap * sizeof(NodeData));
- _RYML_CB_FREE(m_callbacks, m_buf, NodeData, m_cap);
- }
- size_t first = m_cap, del = cap - m_cap;
- m_cap = cap;
- m_buf = buf;
- _clear_range(first, del);
- if(m_free_head != NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, m_buf != nullptr);
- _RYML_CB_ASSERT(m_callbacks, m_free_tail != NONE);
- m_buf[m_free_tail].m_next_sibling = first;
- m_buf[first].m_prev_sibling = m_free_tail;
- m_free_tail = cap-1;
- }
- else
- {
- _RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE);
- m_free_head = first;
- m_free_tail = cap-1;
- }
- _RYML_CB_ASSERT(m_callbacks, m_free_head == NONE || (m_free_head >= 0 && m_free_head < cap));
- _RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE || (m_free_tail >= 0 && m_free_tail < cap));
-
- if( ! m_size)
- _claim_root();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-void Tree::clear()
-{
- _clear_range(0, m_cap);
- m_size = 0;
- if(m_buf)
- {
- _RYML_CB_ASSERT(m_callbacks, m_cap >= 0);
- m_free_head = 0;
- m_free_tail = m_cap-1;
- _claim_root();
- }
- else
- {
- m_free_head = NONE;
- m_free_tail = NONE;
- }
- for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
- m_tag_directives[i] = {};
-}
-
-void Tree::_claim_root()
-{
- size_t r = _claim();
- _RYML_CB_ASSERT(m_callbacks, r == 0);
- _set_hierarchy(r, NONE, NONE);
-}
-
-
-//-----------------------------------------------------------------------------
-void Tree::_clear_range(size_t first, size_t num)
-{
- if(num == 0)
- return; // prevent overflow when subtracting
- _RYML_CB_ASSERT(m_callbacks, first >= 0 && first + num <= m_cap);
- memset(m_buf + first, 0, num * sizeof(NodeData)); // TODO we should not need this
- for(size_t i = first, e = first + num; i < e; ++i)
- {
- _clear(i);
- NodeData *n = m_buf + i;
- n->m_prev_sibling = i - 1;
- n->m_next_sibling = i + 1;
- }
- m_buf[first + num - 1].m_next_sibling = NONE;
-}
-
-C4_SUPPRESS_WARNING_GCC_POP
-
-
-//-----------------------------------------------------------------------------
-void Tree::_release(size_t i)
-{
- _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
-
- _rem_hierarchy(i);
- _free_list_add(i);
- _clear(i);
-
- --m_size;
-}
-
-//-----------------------------------------------------------------------------
-// add to the front of the free list
-void Tree::_free_list_add(size_t i)
-{
- _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
- NodeData &C4_RESTRICT w = m_buf[i];
-
- w.m_parent = NONE;
- w.m_next_sibling = m_free_head;
- w.m_prev_sibling = NONE;
- if(m_free_head != NONE)
- m_buf[m_free_head].m_prev_sibling = i;
- m_free_head = i;
- if(m_free_tail == NONE)
- m_free_tail = m_free_head;
-}
-
-void Tree::_free_list_rem(size_t i)
-{
- if(m_free_head == i)
- m_free_head = _p(i)->m_next_sibling;
- _rem_hierarchy(i);
-}
-
-//-----------------------------------------------------------------------------
-size_t Tree::_claim()
-{
- if(m_free_head == NONE || m_buf == nullptr)
- {
- size_t sz = 2 * m_cap;
- sz = sz ? sz : 16;
- reserve(sz);
- _RYML_CB_ASSERT(m_callbacks, m_free_head != NONE);
- }
-
- _RYML_CB_ASSERT(m_callbacks, m_size < m_cap);
- _RYML_CB_ASSERT(m_callbacks, m_free_head >= 0 && m_free_head < m_cap);
-
- size_t ichild = m_free_head;
- NodeData *child = m_buf + ichild;
-
- ++m_size;
- m_free_head = child->m_next_sibling;
- if(m_free_head == NONE)
- {
- m_free_tail = NONE;
- _RYML_CB_ASSERT(m_callbacks, m_size == m_cap);
- }
-
- _clear(ichild);
-
- return ichild;
-}
-
-//-----------------------------------------------------------------------------
-
-C4_SUPPRESS_WARNING_GCC_PUSH
-C4_SUPPRESS_WARNING_CLANG_PUSH
-C4_SUPPRESS_WARNING_CLANG("-Wnull-dereference")
-#if defined(__GNUC__) && (__GNUC__ >= 6)
-C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
-#endif
-
-void Tree::_set_hierarchy(size_t ichild, size_t iparent, size_t iprev_sibling)
-{
- _RYML_CB_ASSERT(m_callbacks, iparent == NONE || (iparent >= 0 && iparent < m_cap));
- _RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE || (iprev_sibling >= 0 && iprev_sibling < m_cap));
-
- NodeData *C4_RESTRICT child = get(ichild);
-
- child->m_parent = iparent;
- child->m_prev_sibling = NONE;
- child->m_next_sibling = NONE;
-
- if(iparent == NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, ichild == 0);
- _RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE);
- }
-
- if(iparent == NONE)
- return;
-
- size_t inext_sibling = iprev_sibling != NONE ? next_sibling(iprev_sibling) : first_child(iparent);
- NodeData *C4_RESTRICT parent = get(iparent);
- NodeData *C4_RESTRICT psib = get(iprev_sibling);
- NodeData *C4_RESTRICT nsib = get(inext_sibling);
-
- if(psib)
- {
- _RYML_CB_ASSERT(m_callbacks, next_sibling(iprev_sibling) == id(nsib));
- child->m_prev_sibling = id(psib);
- psib->m_next_sibling = id(child);
- _RYML_CB_ASSERT(m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling == NONE);
- }
-
- if(nsib)
- {
- _RYML_CB_ASSERT(m_callbacks, prev_sibling(inext_sibling) == id(psib));
- child->m_next_sibling = id(nsib);
- nsib->m_prev_sibling = id(child);
- _RYML_CB_ASSERT(m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling == NONE);
- }
-
- if(parent->m_first_child == NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, parent->m_last_child == NONE);
- parent->m_first_child = id(child);
- parent->m_last_child = id(child);
- }
- else
- {
- if(child->m_next_sibling == parent->m_first_child)
- parent->m_first_child = id(child);
-
- if(child->m_prev_sibling == parent->m_last_child)
- parent->m_last_child = id(child);
- }
-}
-
-C4_SUPPRESS_WARNING_GCC_POP
-C4_SUPPRESS_WARNING_CLANG_POP
-
-
-//-----------------------------------------------------------------------------
-void Tree::_rem_hierarchy(size_t i)
-{
- _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
-
- NodeData &C4_RESTRICT w = m_buf[i];
-
- // remove from the parent
- if(w.m_parent != NONE)
- {
- NodeData &C4_RESTRICT p = m_buf[w.m_parent];
- if(p.m_first_child == i)
- {
- p.m_first_child = w.m_next_sibling;
- }
- if(p.m_last_child == i)
- {
- p.m_last_child = w.m_prev_sibling;
- }
- }
-
- // remove from the used list
- if(w.m_prev_sibling != NONE)
- {
- NodeData *C4_RESTRICT prev = get(w.m_prev_sibling);
- prev->m_next_sibling = w.m_next_sibling;
- }
- if(w.m_next_sibling != NONE)
- {
- NodeData *C4_RESTRICT next = get(w.m_next_sibling);
- next->m_prev_sibling = w.m_prev_sibling;
- }
-}
-
-//-----------------------------------------------------------------------------
-void Tree::reorder()
-{
- size_t r = root_id();
- _do_reorder(&r, 0);
-}
-
-//-----------------------------------------------------------------------------
-size_t Tree::_do_reorder(size_t *node, size_t count)
-{
- // swap this node if it's not in place
- if(*node != count)
- {
- _swap(*node, count);
- *node = count;
- }
- ++count; // bump the count from this node
-
- // now descend in the hierarchy
- for(size_t i = first_child(*node); i != NONE; i = next_sibling(i))
- {
- // this child may have been relocated to a different index,
- // so get an updated version
- count = _do_reorder(&i, count);
- }
- return count;
-}
-
-//-----------------------------------------------------------------------------
-void Tree::_swap(size_t n_, size_t m_)
-{
- _RYML_CB_ASSERT(m_callbacks, (parent(n_) != NONE) || type(n_) == NOTYPE);
- _RYML_CB_ASSERT(m_callbacks, (parent(m_) != NONE) || type(m_) == NOTYPE);
- NodeType tn = type(n_);
- NodeType tm = type(m_);
- if(tn != NOTYPE && tm != NOTYPE)
- {
- _swap_props(n_, m_);
- _swap_hierarchy(n_, m_);
- }
- else if(tn == NOTYPE && tm != NOTYPE)
- {
- _copy_props(n_, m_);
- _free_list_rem(n_);
- _copy_hierarchy(n_, m_);
- _clear(m_);
- _free_list_add(m_);
- }
- else if(tn != NOTYPE && tm == NOTYPE)
- {
- _copy_props(m_, n_);
- _free_list_rem(m_);
- _copy_hierarchy(m_, n_);
- _clear(n_);
- _free_list_add(n_);
- }
- else
- {
- C4_NEVER_REACH();
- }
-}
-
-//-----------------------------------------------------------------------------
-void Tree::_swap_hierarchy(size_t ia, size_t ib)
-{
- if(ia == ib) return;
-
- for(size_t i = first_child(ia); i != NONE; i = next_sibling(i))
- {
- if(i == ib || i == ia)
- continue;
- _p(i)->m_parent = ib;
- }
-
- for(size_t i = first_child(ib); i != NONE; i = next_sibling(i))
- {
- if(i == ib || i == ia)
- continue;
- _p(i)->m_parent = ia;
- }
-
- auto & C4_RESTRICT a = *_p(ia);
- auto & C4_RESTRICT b = *_p(ib);
- auto & C4_RESTRICT pa = *_p(a.m_parent);
- auto & C4_RESTRICT pb = *_p(b.m_parent);
-
- if(&pa == &pb)
- {
- if((pa.m_first_child == ib && pa.m_last_child == ia)
- ||
- (pa.m_first_child == ia && pa.m_last_child == ib))
- {
- std::swap(pa.m_first_child, pa.m_last_child);
- }
- else
- {
- bool changed = false;
- if(pa.m_first_child == ia)
- {
- pa.m_first_child = ib;
- changed = true;
- }
- if(pa.m_last_child == ia)
- {
- pa.m_last_child = ib;
- changed = true;
- }
- if(pb.m_first_child == ib && !changed)
- {
- pb.m_first_child = ia;
- }
- if(pb.m_last_child == ib && !changed)
- {
- pb.m_last_child = ia;
- }
- }
- }
- else
- {
- if(pa.m_first_child == ia)
- pa.m_first_child = ib;
- if(pa.m_last_child == ia)
- pa.m_last_child = ib;
- if(pb.m_first_child == ib)
- pb.m_first_child = ia;
- if(pb.m_last_child == ib)
- pb.m_last_child = ia;
- }
- std::swap(a.m_first_child , b.m_first_child);
- std::swap(a.m_last_child , b.m_last_child);
-
- if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
- a.m_next_sibling != ib && b.m_next_sibling != ia)
- {
- if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib)
- _p(a.m_prev_sibling)->m_next_sibling = ib;
- if(a.m_next_sibling != NONE && a.m_next_sibling != ib)
- _p(a.m_next_sibling)->m_prev_sibling = ib;
- if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia)
- _p(b.m_prev_sibling)->m_next_sibling = ia;
- if(b.m_next_sibling != NONE && b.m_next_sibling != ia)
- _p(b.m_next_sibling)->m_prev_sibling = ia;
- std::swap(a.m_prev_sibling, b.m_prev_sibling);
- std::swap(a.m_next_sibling, b.m_next_sibling);
- }
- else
- {
- if(a.m_next_sibling == ib) // n will go after m
- {
- _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling == ia);
- if(a.m_prev_sibling != NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ib);
- _p(a.m_prev_sibling)->m_next_sibling = ib;
- }
- if(b.m_next_sibling != NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ia);
- _p(b.m_next_sibling)->m_prev_sibling = ia;
- }
- size_t ns = b.m_next_sibling;
- b.m_prev_sibling = a.m_prev_sibling;
- b.m_next_sibling = ia;
- a.m_prev_sibling = ib;
- a.m_next_sibling = ns;
- }
- else if(a.m_prev_sibling == ib) // m will go after n
- {
- _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling == ia);
- if(b.m_prev_sibling != NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ia);
- _p(b.m_prev_sibling)->m_next_sibling = ia;
- }
- if(a.m_next_sibling != NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ib);
- _p(a.m_next_sibling)->m_prev_sibling = ib;
- }
- size_t ns = b.m_prev_sibling;
- a.m_prev_sibling = b.m_prev_sibling;
- a.m_next_sibling = ib;
- b.m_prev_sibling = ia;
- b.m_next_sibling = ns;
- }
- else
- {
- C4_NEVER_REACH();
- }
- }
- _RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ia);
- _RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ia);
- _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ib);
- _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ib);
-
- if(a.m_parent != ib && b.m_parent != ia)
- {
- std::swap(a.m_parent, b.m_parent);
- }
- else
- {
- if(a.m_parent == ib && b.m_parent != ia)
- {
- a.m_parent = b.m_parent;
- b.m_parent = ia;
- }
- else if(a.m_parent != ib && b.m_parent == ia)
- {
- b.m_parent = a.m_parent;
- a.m_parent = ib;
- }
- else
- {
- C4_NEVER_REACH();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-void Tree::_copy_hierarchy(size_t dst_, size_t src_)
-{
- auto const& C4_RESTRICT src = *_p(src_);
- auto & C4_RESTRICT dst = *_p(dst_);
- auto & C4_RESTRICT prt = *_p(src.m_parent);
- for(size_t i = src.m_first_child; i != NONE; i = next_sibling(i))
- {
- _p(i)->m_parent = dst_;
- }
- if(src.m_prev_sibling != NONE)
- {
- _p(src.m_prev_sibling)->m_next_sibling = dst_;
- }
- if(src.m_next_sibling != NONE)
- {
- _p(src.m_next_sibling)->m_prev_sibling = dst_;
- }
- if(prt.m_first_child == src_)
- {
- prt.m_first_child = dst_;
- }
- if(prt.m_last_child == src_)
- {
- prt.m_last_child = dst_;
- }
- dst.m_parent = src.m_parent;
- dst.m_first_child = src.m_first_child;
- dst.m_last_child = src.m_last_child;
- dst.m_prev_sibling = src.m_prev_sibling;
- dst.m_next_sibling = src.m_next_sibling;
-}
-
-//-----------------------------------------------------------------------------
-void Tree::_swap_props(size_t n_, size_t m_)
-{
- NodeData &C4_RESTRICT n = *_p(n_);
- NodeData &C4_RESTRICT m = *_p(m_);
- std::swap(n.m_type, m.m_type);
- std::swap(n.m_key, m.m_key);
- std::swap(n.m_val, m.m_val);
-}
-
-//-----------------------------------------------------------------------------
-void Tree::move(size_t node, size_t after)
-{
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, node != after);
- _RYML_CB_ASSERT(m_callbacks, ! is_root(node));
- _RYML_CB_ASSERT(m_callbacks, (after == NONE) || (has_sibling(node, after) && has_sibling(after, node)));
-
- _rem_hierarchy(node);
- _set_hierarchy(node, parent(node), after);
-}
-
-//-----------------------------------------------------------------------------
-
-void Tree::move(size_t node, size_t new_parent, size_t after)
-{
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, node != after);
- _RYML_CB_ASSERT(m_callbacks, new_parent != NONE);
- _RYML_CB_ASSERT(m_callbacks, new_parent != node);
- _RYML_CB_ASSERT(m_callbacks, new_parent != after);
- _RYML_CB_ASSERT(m_callbacks, ! is_root(node));
-
- _rem_hierarchy(node);
- _set_hierarchy(node, new_parent, after);
-}
-
-size_t Tree::move(Tree *src, size_t node, size_t new_parent, size_t after)
-{
- _RYML_CB_ASSERT(m_callbacks, src != nullptr);
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, new_parent != NONE);
- _RYML_CB_ASSERT(m_callbacks, new_parent != after);
-
- size_t dup = duplicate(src, node, new_parent, after);
- src->remove(node);
- return dup;
-}
-
-void Tree::set_root_as_stream()
-{
- size_t root = root_id();
- if(is_stream(root))
- return;
- // don't use _add_flags() because it's checked and will fail
- if(!has_children(root))
- {
- if(is_val(root))
- {
- _p(root)->m_type.add(SEQ);
- size_t next_doc = append_child(root);
- _copy_props_wo_key(next_doc, root);
- _p(next_doc)->m_type.add(DOC);
- _p(next_doc)->m_type.rem(SEQ);
- }
- _p(root)->m_type = STREAM;
- return;
- }
- _RYML_CB_ASSERT(m_callbacks, !has_key(root));
- size_t next_doc = append_child(root);
- _copy_props_wo_key(next_doc, root);
- _add_flags(next_doc, DOC);
- for(size_t prev = NONE, ch = first_child(root), next = next_sibling(ch); ch != NONE; )
- {
- if(ch == next_doc)
- break;
- move(ch, next_doc, prev);
- prev = ch;
- ch = next;
- next = next_sibling(next);
- }
- _p(root)->m_type = STREAM;
-}
-
-
-//-----------------------------------------------------------------------------
-void Tree::remove_children(size_t node)
-{
- _RYML_CB_ASSERT(m_callbacks, get(node) != nullptr);
- size_t ich = get(node)->m_first_child;
- while(ich != NONE)
- {
- remove_children(ich);
- _RYML_CB_ASSERT(m_callbacks, get(ich) != nullptr);
- size_t next = get(ich)->m_next_sibling;
- _release(ich);
- if(ich == get(node)->m_last_child)
- break;
- ich = next;
- }
-}
-
-bool Tree::change_type(size_t node, NodeType type)
-{
- _RYML_CB_ASSERT(m_callbacks, type.is_val() || type.is_map() || type.is_seq());
- _RYML_CB_ASSERT(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1);
- _RYML_CB_ASSERT(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()));
- NodeData *d = _p(node);
- if(type.is_map() && is_map(node))
- return false;
- else if(type.is_seq() && is_seq(node))
- return false;
- else if(type.is_val() && is_val(node))
- return false;
- d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type;
- remove_children(node);
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-size_t Tree::duplicate(size_t node, size_t parent, size_t after)
-{
- return duplicate(this, node, parent, after);
-}
-
-size_t Tree::duplicate(Tree const* src, size_t node, size_t parent, size_t after)
-{
- _RYML_CB_ASSERT(m_callbacks, src != nullptr);
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, parent != NONE);
- _RYML_CB_ASSERT(m_callbacks, ! src->is_root(node));
-
- size_t copy = _claim();
-
- _copy_props(copy, src, node);
- _set_hierarchy(copy, parent, after);
- duplicate_children(src, node, copy, NONE);
-
- return copy;
-}
-
-//-----------------------------------------------------------------------------
-size_t Tree::duplicate_children(size_t node, size_t parent, size_t after)
-{
- return duplicate_children(this, node, parent, after);
-}
-
-size_t Tree::duplicate_children(Tree const* src, size_t node, size_t parent, size_t after)
-{
- _RYML_CB_ASSERT(m_callbacks, src != nullptr);
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, parent != NONE);
- _RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after));
-
- size_t prev = after;
- for(size_t i = src->first_child(node); i != NONE; i = src->next_sibling(i))
- {
- prev = duplicate(src, i, parent, prev);
- }
-
- return prev;
-}
-
-//-----------------------------------------------------------------------------
-void Tree::duplicate_contents(size_t node, size_t where)
-{
- duplicate_contents(this, node, where);
-}
-
-void Tree::duplicate_contents(Tree const *src, size_t node, size_t where)
-{
- _RYML_CB_ASSERT(m_callbacks, src != nullptr);
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, where != NONE);
- _copy_props_wo_key(where, src, node);
- duplicate_children(src, node, where, last_child(where));
-}
-
-//-----------------------------------------------------------------------------
-size_t Tree::duplicate_children_no_rep(size_t node, size_t parent, size_t after)
-{
- return duplicate_children_no_rep(this, node, parent, after);
-}
-
-size_t Tree::duplicate_children_no_rep(Tree const *src, size_t node, size_t parent, size_t after)
-{
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, parent != NONE);
- _RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after));
-
- // don't loop using pointers as there may be a relocation
-
- // find the position where "after" is
- size_t after_pos = NONE;
- if(after != NONE)
- {
- for(size_t i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))
- {
- if(i == after)
- {
- after_pos = icount;
- break;
- }
- }
- _RYML_CB_ASSERT(m_callbacks, after_pos != NONE);
- }
-
- // for each child to be duplicated...
- size_t prev = after;
- for(size_t i = src->first_child(node), icount = 0; i != NONE; ++icount, i = src->next_sibling(i))
- {
- if(is_seq(parent))
- {
- prev = duplicate(i, parent, prev);
- }
- else
- {
- _RYML_CB_ASSERT(m_callbacks, is_map(parent));
- // does the parent already have a node with key equal to that of the current duplicate?
- size_t rep = NONE, rep_pos = NONE;
- for(size_t j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j))
- {
- if(key(j) == key(i))
- {
- rep = j;
- rep_pos = jcount;
- break;
- }
- }
- if(rep == NONE) // there is no repetition; just duplicate
- {
- prev = duplicate(src, i, parent, prev);
- }
- else // yes, there is a repetition
- {
- if(after_pos != NONE && rep_pos < after_pos)
- {
- // rep is located before the node which will be inserted,
- // and will be overridden by the duplicate. So replace it.
- remove(rep);
- prev = duplicate(src, i, parent, prev);
- }
- else if(prev == NONE)
- {
- // first iteration with prev = after = NONE and repetition
- prev = rep;
- }
- else if(rep != prev)
- {
- // rep is located after the node which will be inserted
- // and overrides it. So move the rep into this node's place.
- move(rep, prev);
- prev = rep;
- }
- } // there's a repetition
- }
- }
-
- return prev;
-}
-
-
-//-----------------------------------------------------------------------------
-
-void Tree::merge_with(Tree const *src, size_t src_node, size_t dst_node)
-{
- _RYML_CB_ASSERT(m_callbacks, src != nullptr);
- if(src_node == NONE)
- src_node = src->root_id();
- if(dst_node == NONE)
- dst_node = root_id();
- _RYML_CB_ASSERT(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node));
-
- if(src->has_val(src_node))
- {
- if( ! has_val(dst_node))
- {
- if(has_children(dst_node))
- remove_children(dst_node);
- }
- if(src->is_keyval(src_node))
- _copy_props(dst_node, src, src_node);
- else if(src->is_val(src_node))
- _copy_props_wo_key(dst_node, src, src_node);
- else
- C4_NEVER_REACH();
- }
- else if(src->is_seq(src_node))
- {
- if( ! is_seq(dst_node))
- {
- if(has_children(dst_node))
- remove_children(dst_node);
- _clear_type(dst_node);
- if(src->has_key(src_node))
- to_seq(dst_node, src->key(src_node));
- else
- to_seq(dst_node);
- }
- for(size_t sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
- {
- size_t dch = append_child(dst_node);
- _copy_props_wo_key(dch, src, sch);
- merge_with(src, sch, dch);
- }
- }
- else if(src->is_map(src_node))
- {
- if( ! is_map(dst_node))
- {
- if(has_children(dst_node))
- remove_children(dst_node);
- _clear_type(dst_node);
- if(src->has_key(src_node))
- to_map(dst_node, src->key(src_node));
- else
- to_map(dst_node);
- }
- for(size_t sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
- {
- size_t dch = find_child(dst_node, src->key(sch));
- if(dch == NONE)
- {
- dch = append_child(dst_node);
- _copy_props(dch, src, sch);
- }
- merge_with(src, sch, dch);
- }
- }
- else
- {
- C4_NEVER_REACH();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-
-namespace detail {
-/** @todo make this part of the public API, refactoring as appropriate
- * to be able to use the same resolver to handle multiple trees (one
- * at a time) */
-struct ReferenceResolver
-{
- struct refdata
- {
- NodeType type;
- size_t node;
- size_t prev_anchor;
- size_t target;
- size_t parent_ref;
- size_t parent_ref_sibling;
- };
-
- Tree *t;
- /** from the specs: "an alias node refers to the most recent
- * node in the serialization having the specified anchor". So
- * we need to start looking upward from ref nodes.
- *
- * @see http://yaml.org/spec/1.2/spec.html#id2765878 */
- stack<refdata> refs;
-
- ReferenceResolver(Tree *t_) : t(t_), refs(t_->callbacks())
- {
- resolve();
- }
-
- void store_anchors_and_refs()
- {
- // minimize (re-)allocations by counting first
- size_t num_anchors_and_refs = count_anchors_and_refs(t->root_id());
- if(!num_anchors_and_refs)
- return;
- refs.reserve(num_anchors_and_refs);
-
- // now descend through the hierarchy
- _store_anchors_and_refs(t->root_id());
-
- // finally connect the reference list
- size_t prev_anchor = npos;
- size_t count = 0;
- for(auto &rd : refs)
- {
- rd.prev_anchor = prev_anchor;
- if(rd.type.is_anchor())
- prev_anchor = count;
- ++count;
- }
- }
-
- size_t count_anchors_and_refs(size_t n)
- {
- size_t c = 0;
- c += t->has_key_anchor(n);
- c += t->has_val_anchor(n);
- c += t->is_key_ref(n);
- c += t->is_val_ref(n);
- for(size_t ch = t->first_child(n); ch != NONE; ch = t->next_sibling(ch))
- c += count_anchors_and_refs(ch);
- return c;
- }
-
- void _store_anchors_and_refs(size_t n)
- {
- if(t->is_key_ref(n) || t->is_val_ref(n) || (t->has_key(n) && t->key(n) == "<<"))
- {
- if(t->is_seq(n))
- {
- // for merging multiple inheritance targets
- // <<: [ *CENTER, *BIG ]
- for(size_t ich = t->first_child(n); ich != NONE; ich = t->next_sibling(ich))
- {
- RYML_ASSERT(t->num_children(ich) == 0);
- refs.push({VALREF, ich, npos, npos, n, t->next_sibling(n)});
- }
- return;
- }
- if(t->is_key_ref(n) && t->key(n) != "<<") // insert key refs BEFORE inserting val refs
- {
- RYML_CHECK((!t->has_key(n)) || t->key(n).ends_with(t->key_ref(n)));
- refs.push({KEYREF, n, npos, npos, NONE, NONE});
- }
- if(t->is_val_ref(n))
- {
- RYML_CHECK((!t->has_val(n)) || t->val(n).ends_with(t->val_ref(n)));
- refs.push({VALREF, n, npos, npos, NONE, NONE});
- }
- }
- if(t->has_key_anchor(n))
- {
- RYML_CHECK(t->has_key(n));
- refs.push({KEYANCH, n, npos, npos, NONE, NONE});
- }
- if(t->has_val_anchor(n))
- {
- RYML_CHECK(t->has_val(n) || t->is_container(n));
- refs.push({VALANCH, n, npos, npos, NONE, NONE});
- }
- for(size_t ch = t->first_child(n); ch != NONE; ch = t->next_sibling(ch))
- {
- _store_anchors_and_refs(ch);
- }
- }
-
- size_t lookup_(refdata *C4_RESTRICT ra)
- {
- RYML_ASSERT(ra->type.is_key_ref() || ra->type.is_val_ref());
- RYML_ASSERT(ra->type.is_key_ref() != ra->type.is_val_ref());
- csubstr refname;
- if(ra->type.is_val_ref())
- {
- refname = t->val_ref(ra->node);
- }
- else
- {
- RYML_ASSERT(ra->type.is_key_ref());
- refname = t->key_ref(ra->node);
- }
- while(ra->prev_anchor != npos)
- {
- ra = &refs[ra->prev_anchor];
- if(t->has_anchor(ra->node, refname))
- return ra->node;
- }
-
- #ifndef RYML_ERRMSG_SIZE
- #define RYML_ERRMSG_SIZE 1024
- #endif
-
- char errmsg[RYML_ERRMSG_SIZE];
- snprintf(errmsg, RYML_ERRMSG_SIZE, "anchor does not exist: '%.*s'",
- static_cast<int>(refname.size()), refname.data());
- c4::yml::error(errmsg);
- return NONE;
- }
-
- void resolve()
- {
- store_anchors_and_refs();
- if(refs.empty())
- return;
-
- /* from the specs: "an alias node refers to the most recent
- * node in the serialization having the specified anchor". So
- * we need to start looking upward from ref nodes.
- *
- * @see http://yaml.org/spec/1.2/spec.html#id2765878 */
- for(size_t i = 0, e = refs.size(); i < e; ++i)
- {
- auto &C4_RESTRICT rd = refs.top(i);
- if( ! rd.type.is_ref())
- continue;
- rd.target = lookup_(&rd);
- }
- }
-
-}; // ReferenceResolver
-} // namespace detail
-
-void Tree::resolve()
-{
- if(m_size == 0)
- return;
-
- detail::ReferenceResolver rr(this);
-
- // insert the resolved references
- size_t prev_parent_ref = NONE;
- size_t prev_parent_ref_after = NONE;
- for(auto const& C4_RESTRICT rd : rr.refs)
- {
- if( ! rd.type.is_ref())
- continue;
- if(rd.parent_ref != NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, is_seq(rd.parent_ref));
- size_t after, p = parent(rd.parent_ref);
- if(prev_parent_ref != rd.parent_ref)
- {
- after = rd.parent_ref;//prev_sibling(rd.parent_ref_sibling);
- prev_parent_ref_after = after;
- }
- else
- {
- after = prev_parent_ref_after;
- }
- prev_parent_ref = rd.parent_ref;
- prev_parent_ref_after = duplicate_children_no_rep(rd.target, p, after);
- remove(rd.node);
- }
- else
- {
- if(has_key(rd.node) && is_key_ref(rd.node) && key(rd.node) == "<<")
- {
- _RYML_CB_ASSERT(m_callbacks, is_keyval(rd.node));
- size_t p = parent(rd.node);
- size_t after = prev_sibling(rd.node);
- duplicate_children_no_rep(rd.target, p, after);
- remove(rd.node);
- }
- else if(rd.type.is_key_ref())
- {
- _RYML_CB_ASSERT(m_callbacks, is_key_ref(rd.node));
- _RYML_CB_ASSERT(m_callbacks, has_key_anchor(rd.target) || has_val_anchor(rd.target));
- if(has_val_anchor(rd.target) && val_anchor(rd.target) == key_ref(rd.node))
- {
- _RYML_CB_CHECK(m_callbacks, !is_container(rd.target));
- _RYML_CB_CHECK(m_callbacks, has_val(rd.target));
- _p(rd.node)->m_key.scalar = val(rd.target);
- _add_flags(rd.node, KEY);
- }
- else
- {
- _RYML_CB_CHECK(m_callbacks, key_anchor(rd.target) == key_ref(rd.node));
- _p(rd.node)->m_key.scalar = key(rd.target);
- _add_flags(rd.node, VAL);
- }
- }
- else
- {
- _RYML_CB_ASSERT(m_callbacks, rd.type.is_val_ref());
- if(has_key_anchor(rd.target) && key_anchor(rd.target) == val_ref(rd.node))
- {
- _RYML_CB_CHECK(m_callbacks, !is_container(rd.target));
- _RYML_CB_CHECK(m_callbacks, has_val(rd.target));
- _p(rd.node)->m_val.scalar = key(rd.target);
- _add_flags(rd.node, VAL);
- }
- else
- {
- duplicate_contents(rd.target, rd.node);
- }
- }
- }
- }
-
- // clear anchors and refs
- for(auto const& C4_RESTRICT ar : rr.refs)
- {
- rem_anchor_ref(ar.node);
- if(ar.parent_ref != NONE)
- if(type(ar.parent_ref) != NOTYPE)
- remove(ar.parent_ref);
- }
-
-}
-
-//-----------------------------------------------------------------------------
-
-size_t Tree::num_children(size_t node) const
-{
- size_t count = 0;
- for(size_t i = first_child(node); i != NONE; i = next_sibling(i))
- ++count;
- return count;
-}
-
-size_t Tree::child(size_t node, size_t pos) const
-{
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- size_t count = 0;
- for(size_t i = first_child(node); i != NONE; i = next_sibling(i))
- {
- if(count++ == pos)
- return i;
- }
- return NONE;
-}
-
-size_t Tree::child_pos(size_t node, size_t ch) const
-{
- size_t count = 0;
- for(size_t i = first_child(node); i != NONE; i = next_sibling(i))
- {
- if(i == ch)
- return count;
- ++count;
- }
- return npos;
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma GCC diagnostic ignored "-Wnull-dereference"
-#elif defined(__GNUC__)
-# pragma GCC diagnostic push
-# if __GNUC__ >= 6
-# pragma GCC diagnostic ignored "-Wnull-dereference"
-# endif
-#endif
-
-size_t Tree::find_child(size_t node, csubstr const& name) const
-{
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- _RYML_CB_ASSERT(m_callbacks, is_map(node));
- if(get(node)->m_first_child == NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child == NONE);
- return NONE;
- }
- else
- {
- _RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child != NONE);
- }
- for(size_t i = first_child(node); i != NONE; i = next_sibling(i))
- {
- if(_p(i)->m_key.scalar == name)
- {
- return i;
- }
- }
- return NONE;
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#elif defined(__GNUC__)
-# pragma GCC diagnostic pop
-#endif
-
-
-//-----------------------------------------------------------------------------
-
-void Tree::to_val(size_t node, csubstr val, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node));
- _set_flags(node, VAL|more_flags);
- _p(node)->m_key.clear();
- _p(node)->m_val = val;
-}
-
-void Tree::to_keyval(size_t node, csubstr key, csubstr val, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));
- _set_flags(node, KEYVAL|more_flags);
- _p(node)->m_key = key;
- _p(node)->m_val = val;
-}
-
-void Tree::to_map(size_t node, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node)); // parent must not have children with keys
- _set_flags(node, MAP|more_flags);
- _p(node)->m_key.clear();
- _p(node)->m_val.clear();
-}
-
-void Tree::to_map(size_t node, csubstr key, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));
- _set_flags(node, KEY|MAP|more_flags);
- _p(node)->m_key = key;
- _p(node)->m_val.clear();
-}
-
-void Tree::to_seq(size_t node, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_seq(node));
- _set_flags(node, SEQ|more_flags);
- _p(node)->m_key.clear();
- _p(node)->m_val.clear();
-}
-
-void Tree::to_seq(size_t node, csubstr key, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));
- _set_flags(node, KEY|SEQ|more_flags);
- _p(node)->m_key = key;
- _p(node)->m_val.clear();
-}
-
-void Tree::to_doc(size_t node, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _set_flags(node, DOC|more_flags);
- _p(node)->m_key.clear();
- _p(node)->m_val.clear();
-}
-
-void Tree::to_stream(size_t node, type_bits more_flags)
-{
- _RYML_CB_ASSERT(m_callbacks, ! has_children(node));
- _set_flags(node, STREAM|more_flags);
- _p(node)->m_key.clear();
- _p(node)->m_val.clear();
-}
-
-
-//-----------------------------------------------------------------------------
-size_t Tree::num_tag_directives() const
-{
- // this assumes we have a very small number of tag directives
- for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
- if(m_tag_directives[i].handle.empty())
- return i;
- return RYML_MAX_TAG_DIRECTIVES;
-}
-
-void Tree::clear_tag_directives()
-{
- for(TagDirective &td : m_tag_directives)
- td = {};
-}
-
-size_t Tree::add_tag_directive(TagDirective const& td)
-{
- _RYML_CB_CHECK(m_callbacks, !td.handle.empty());
- _RYML_CB_CHECK(m_callbacks, !td.prefix.empty());
- _RYML_CB_ASSERT(m_callbacks, td.handle.begins_with('!'));
- _RYML_CB_ASSERT(m_callbacks, td.handle.ends_with('!'));
- // https://yaml.org/spec/1.2.2/#rule-ns-word-char
- _RYML_CB_ASSERT(m_callbacks, td.handle == '!' || td.handle == "!!" || td.handle.trim('!').first_not_of("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-") == npos);
- size_t pos = num_tag_directives();
- _RYML_CB_CHECK(m_callbacks, pos < RYML_MAX_TAG_DIRECTIVES);
- m_tag_directives[pos] = td;
- return pos;
-}
-
-size_t Tree::resolve_tag(substr output, csubstr tag, size_t node_id) const
-{
- // lookup from the end. We want to find the first directive that
- // matches the tag and has a target node id leq than the given
- // node_id.
- for(size_t i = RYML_MAX_TAG_DIRECTIVES-1; i != (size_t)-1; --i)
- {
- auto const& td = m_tag_directives[i];
- if(td.handle.empty())
- continue;
- if(tag.begins_with(td.handle) && td.next_node_id <= node_id)
- {
- _RYML_CB_ASSERT(m_callbacks, tag.len >= td.handle.len);
- csubstr rest = tag.sub(td.handle.len);
- size_t len = 1u + td.prefix.len + rest.len + 1u;
- size_t numpc = rest.count('%');
- if(numpc == 0)
- {
- if(len <= output.len)
- {
- output.str[0] = '<';
- memcpy(1u + output.str, td.prefix.str, td.prefix.len);
- memcpy(1u + output.str + td.prefix.len, rest.str, rest.len);
- output.str[1u + td.prefix.len + rest.len] = '>';
- }
- }
- else
- {
- // need to decode URI % sequences
- size_t pos = rest.find('%');
- _RYML_CB_ASSERT(m_callbacks, pos != npos);
- do {
- size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);
- if(next == npos)
- next = rest.len;
- _RYML_CB_CHECK(m_callbacks, pos+1 < next);
- _RYML_CB_CHECK(m_callbacks, pos+1 + 2 <= next);
- size_t delta = next - (pos+1);
- len -= delta;
- pos = rest.find('%', pos+1);
- } while(pos != npos);
- if(len <= output.len)
- {
- size_t prev = 0, wpos = 0;
- auto appendstr = [&](csubstr s) { memcpy(output.str + wpos, s.str, s.len); wpos += s.len; };
- auto appendchar = [&](char c) { output.str[wpos++] = c; };
- appendchar('<');
- appendstr(td.prefix);
- pos = rest.find('%');
- _RYML_CB_ASSERT(m_callbacks, pos != npos);
- do {
- size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);
- if(next == npos)
- next = rest.len;
- _RYML_CB_CHECK(m_callbacks, pos+1 < next);
- _RYML_CB_CHECK(m_callbacks, pos+1 + 2 <= next);
- uint8_t val;
- if(C4_UNLIKELY(!read_hex(rest.range(pos+1, next), &val) || val > 127))
- _RYML_CB_ERR(m_callbacks, "invalid URI character");
- appendstr(rest.range(prev, pos));
- appendchar((char)val);
- prev = next;
- pos = rest.find('%', pos+1);
- } while(pos != npos);
- _RYML_CB_ASSERT(m_callbacks, pos == npos);
- _RYML_CB_ASSERT(m_callbacks, prev > 0);
- _RYML_CB_ASSERT(m_callbacks, rest.len >= prev);
- appendstr(rest.sub(prev));
- appendchar('>');
- _RYML_CB_ASSERT(m_callbacks, wpos == len);
- }
- }
- return len;
- }
- }
- return 0; // return 0 to signal that the tag is local and cannot be resolved
-}
-
-namespace {
-csubstr _transform_tag(Tree *t, csubstr tag, size_t node)
-{
- size_t required_size = t->resolve_tag(substr{}, tag, node);
- if(!required_size)
- return tag;
- const char *prev_arena = t->arena().str;
- substr buf = t->alloc_arena(required_size);
- _RYML_CB_ASSERT(t->m_callbacks, t->arena().str == prev_arena);
- size_t actual_size = t->resolve_tag(buf, tag, node);
- _RYML_CB_ASSERT(t->m_callbacks, actual_size <= required_size);
- return buf.first(actual_size);
-}
-void _resolve_tags(Tree *t, size_t node)
-{
- for(size_t child = t->first_child(node); child != NONE; child = t->next_sibling(child))
- {
- if(t->has_key(child) && t->has_key_tag(child))
- t->set_key_tag(child, _transform_tag(t, t->key_tag(child), child));
- if(t->has_val(child) && t->has_val_tag(child))
- t->set_val_tag(child, _transform_tag(t, t->val_tag(child), child));
- _resolve_tags(t, child);
- }
-}
-size_t _count_resolved_tags_size(Tree const* t, size_t node)
-{
- size_t sz = 0;
- for(size_t child = t->first_child(node); child != NONE; child = t->next_sibling(child))
- {
- if(t->has_key(child) && t->has_key_tag(child))
- sz += t->resolve_tag(substr{}, t->key_tag(child), child);
- if(t->has_val(child) && t->has_val_tag(child))
- sz += t->resolve_tag(substr{}, t->val_tag(child), child);
- sz += _count_resolved_tags_size(t, child);
- }
- return sz;
-}
-} // namespace
-
-void Tree::resolve_tags()
-{
- if(empty())
- return;
- if(num_tag_directives() == 0)
- return;
- size_t needed_size = _count_resolved_tags_size(this, root_id());
- if(needed_size)
- reserve_arena(arena_size() + needed_size);
- _resolve_tags(this, root_id());
-}
-
-
-//-----------------------------------------------------------------------------
-
-csubstr Tree::lookup_result::resolved() const
-{
- csubstr p = path.first(path_pos);
- if(p.ends_with('.'))
- p = p.first(p.len-1);
- return p;
-}
-
-csubstr Tree::lookup_result::unresolved() const
-{
- return path.sub(path_pos);
-}
-
-void Tree::_advance(lookup_result *r, size_t more) const
-{
- r->path_pos += more;
- if(r->path.sub(r->path_pos).begins_with('.'))
- ++r->path_pos;
-}
-
-Tree::lookup_result Tree::lookup_path(csubstr path, size_t start) const
-{
- if(start == NONE)
- start = root_id();
- lookup_result r(path, start);
- if(path.empty())
- return r;
- _lookup_path(&r);
- if(r.target == NONE && r.closest == start)
- r.closest = NONE;
- return r;
-}
-
-size_t Tree::lookup_path_or_modify(csubstr default_value, csubstr path, size_t start)
-{
- size_t target = _lookup_path_or_create(path, start);
- if(parent_is_map(target))
- to_keyval(target, key(target), default_value);
- else
- to_val(target, default_value);
- return target;
-}
-
-size_t Tree::lookup_path_or_modify(Tree const *src, size_t src_node, csubstr path, size_t start)
-{
- size_t target = _lookup_path_or_create(path, start);
- merge_with(src, src_node, target);
- return target;
-}
-
-size_t Tree::_lookup_path_or_create(csubstr path, size_t start)
-{
- if(start == NONE)
- start = root_id();
- lookup_result r(path, start);
- _lookup_path(&r);
- if(r.target != NONE)
- {
- C4_ASSERT(r.unresolved().empty());
- return r.target;
- }
- _lookup_path_modify(&r);
- return r.target;
-}
-
-void Tree::_lookup_path(lookup_result *r) const
-{
- C4_ASSERT( ! r->unresolved().empty());
- _lookup_path_token parent{"", type(r->closest)};
- size_t node;
- do
- {
- node = _next_node(r, &parent);
- if(node != NONE)
- r->closest = node;
- if(r->unresolved().empty())
- {
- r->target = node;
- return;
- }
- } while(node != NONE);
-}
-
-void Tree::_lookup_path_modify(lookup_result *r)
-{
- C4_ASSERT( ! r->unresolved().empty());
- _lookup_path_token parent{"", type(r->closest)};
- size_t node;
- do
- {
- node = _next_node_modify(r, &parent);
- if(node != NONE)
- r->closest = node;
- if(r->unresolved().empty())
- {
- r->target = node;
- return;
- }
- } while(node != NONE);
-}
-
-size_t Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const
-{
- _lookup_path_token token = _next_token(r, *parent);
- if( ! token)
- return NONE;
-
- size_t node = NONE;
- csubstr prev = token.value;
- if(token.type == MAP || token.type == SEQ)
- {
- _RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('['));
- //_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE);
- _RYML_CB_ASSERT(m_callbacks, is_map(r->closest));
- node = find_child(r->closest, token.value);
- }
- else if(token.type == KEYVAL)
- {
- _RYML_CB_ASSERT(m_callbacks, r->unresolved().empty());
- if(is_map(r->closest))
- node = find_child(r->closest, token.value);
- }
- else if(token.type == KEY)
- {
- _RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'));
- token.value = token.value.offs(1, 1).trim(' ');
- size_t idx = 0;
- _RYML_CB_CHECK(m_callbacks, from_chars(token.value, &idx));
- node = child(r->closest, idx);
- }
- else
- {
- C4_NEVER_REACH();
- }
-
- if(node != NONE)
- {
- *parent = token;
- }
- else
- {
- csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
- r->path_pos -= prev.len;
- if(p.begins_with('.'))
- r->path_pos -= 1u;
- }
-
- return node;
-}
-
-size_t Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
-{
- _lookup_path_token token = _next_token(r, *parent);
- if( ! token)
- return NONE;
-
- size_t node = NONE;
- if(token.type == MAP || token.type == SEQ)
- {
- _RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('['));
- //_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE);
- if( ! is_container(r->closest))
- {
- if(has_key(r->closest))
- to_map(r->closest, key(r->closest));
- else
- to_map(r->closest);
- }
- else
- {
- if(is_map(r->closest))
- node = find_child(r->closest, token.value);
- else
- {
- size_t pos = NONE;
- _RYML_CB_CHECK(m_callbacks, c4::atox(token.value, &pos));
- _RYML_CB_ASSERT(m_callbacks, pos != NONE);
- node = child(r->closest, pos);
- }
- }
- if(node == NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, is_map(r->closest));
- node = append_child(r->closest);
- NodeData *n = _p(node);
- n->m_key.scalar = token.value;
- n->m_type.add(KEY);
- }
- }
- else if(token.type == KEYVAL)
- {
- _RYML_CB_ASSERT(m_callbacks, r->unresolved().empty());
- if(is_map(r->closest))
- {
- node = find_child(r->closest, token.value);
- if(node == NONE)
- node = append_child(r->closest);
- }
- else
- {
- _RYML_CB_ASSERT(m_callbacks, !is_seq(r->closest));
- _add_flags(r->closest, MAP);
- node = append_child(r->closest);
- }
- NodeData *n = _p(node);
- n->m_key.scalar = token.value;
- n->m_val.scalar = "";
- n->m_type.add(KEYVAL);
- }
- else if(token.type == KEY)
- {
- _RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'));
- token.value = token.value.offs(1, 1).trim(' ');
- size_t idx;
- if( ! from_chars(token.value, &idx))
- return NONE;
- if( ! is_container(r->closest))
- {
- if(has_key(r->closest))
- {
- csubstr k = key(r->closest);
- _clear_type(r->closest);
- to_seq(r->closest, k);
- }
- else
- {
- _clear_type(r->closest);
- to_seq(r->closest);
- }
- }
- _RYML_CB_ASSERT(m_callbacks, is_container(r->closest));
- node = child(r->closest, idx);
- if(node == NONE)
- {
- _RYML_CB_ASSERT(m_callbacks, num_children(r->closest) <= idx);
- for(size_t i = num_children(r->closest); i <= idx; ++i)
- {
- node = append_child(r->closest);
- if(i < idx)
- {
- if(is_map(r->closest))
- to_keyval(node, /*"~"*/{}, /*"~"*/{});
- else if(is_seq(r->closest))
- to_val(node, /*"~"*/{});
- }
- }
- }
- }
- else
- {
- C4_NEVER_REACH();
- }
-
- _RYML_CB_ASSERT(m_callbacks, node != NONE);
- *parent = token;
- return node;
-}
-
-/** types of tokens:
- * - seeing "map." ---> "map"/MAP
- * - finishing "scalar" ---> "scalar"/KEYVAL
- * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)
- * - seeing "[n]" ---> "[n]"/KEY
- */
-Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const
-{
- csubstr unres = r->unresolved();
- if(unres.empty())
- return {};
-
- // is it an indexation like [0], [1], etc?
- if(unres.begins_with('['))
- {
- size_t pos = unres.find(']');
- if(pos == csubstr::npos)
- return {};
- csubstr idx = unres.first(pos + 1);
- _advance(r, pos + 1);
- return {idx, KEY};
- }
-
- // no. so it must be a name
- size_t pos = unres.first_of(".[");
- if(pos == csubstr::npos)
- {
- _advance(r, unres.len);
- NodeType t;
- if(( ! parent) || parent.type.is_seq())
- return {unres, VAL};
- return {unres, KEYVAL};
- }
-
- // it's either a map or a seq
- _RYML_CB_ASSERT(m_callbacks, unres[pos] == '.' || unres[pos] == '[');
- if(unres[pos] == '.')
- {
- _RYML_CB_ASSERT(m_callbacks, pos != 0);
- _advance(r, pos + 1);
- return {unres.first(pos), MAP};
- }
-
- _RYML_CB_ASSERT(m_callbacks, unres[pos] == '[');
- _advance(r, pos);
- return {unres.first(pos), SEQ};
-}
-
-
-} // namespace ryml
-} // namespace c4
-
-
-C4_SUPPRESS_WARNING_GCC_POP
-C4_SUPPRESS_WARNING_MSVC_POP
diff --git a/thirdparty/ryml/src/c4/yml/tree.hpp b/thirdparty/ryml/src/c4/yml/tree.hpp
deleted file mode 100644
index 5adc5583a..000000000
--- a/thirdparty/ryml/src/c4/yml/tree.hpp
+++ /dev/null
@@ -1,1495 +0,0 @@
-#ifndef _C4_YML_TREE_HPP_
-#define _C4_YML_TREE_HPP_
-
-
-#include "c4/error.hpp"
-#include "c4/types.hpp"
-#ifndef _C4_YML_COMMON_HPP_
-#include "c4/yml/common.hpp"
-#endif
-
-#include <c4/charconv.hpp>
-#include <cmath>
-#include <limits>
-
-
-C4_SUPPRESS_WARNING_MSVC_PUSH
-C4_SUPPRESS_WARNING_MSVC(4251) // needs to have dll-interface to be used by clients of struct
-C4_SUPPRESS_WARNING_MSVC(4296) // expression is always 'boolean_value'
-C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
-C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
-
-
-namespace c4 {
-namespace yml {
-
-struct NodeScalar;
-struct NodeInit;
-struct NodeData;
-class NodeRef;
-class ConstNodeRef;
-class Tree;
-
-
-/** encode a floating point value to a string. */
-template<class T>
-size_t to_chars_float(substr buf, T val)
-{
- C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wfloat-equal");
- static_assert(std::is_floating_point<T>::value, "must be floating point");
- if(C4_UNLIKELY(std::isnan(val)))
- return to_chars(buf, csubstr(".nan"));
- else if(C4_UNLIKELY(val == std::numeric_limits<T>::infinity()))
- return to_chars(buf, csubstr(".inf"));
- else if(C4_UNLIKELY(val == -std::numeric_limits<T>::infinity()))
- return to_chars(buf, csubstr("-.inf"));
- return to_chars(buf, val);
- C4_SUPPRESS_WARNING_GCC_CLANG_POP
-}
-
-
-/** decode a floating point from string. Accepts special values: .nan,
- * .inf, -.inf */
-template<class T>
-bool from_chars_float(csubstr buf, T *C4_RESTRICT val)
-{
- static_assert(std::is_floating_point<T>::value, "must be floating point");
- if(C4_LIKELY(from_chars(buf, val)))
- {
- return true;
- }
- else if(C4_UNLIKELY(buf == ".nan" || buf == ".NaN" || buf == ".NAN"))
- {
- *val = std::numeric_limits<T>::quiet_NaN();
- return true;
- }
- else if(C4_UNLIKELY(buf == ".inf" || buf == ".Inf" || buf == ".INF"))
- {
- *val = std::numeric_limits<T>::infinity();
- return true;
- }
- else if(C4_UNLIKELY(buf == "-.inf" || buf == "-.Inf" || buf == "-.INF"))
- {
- *val = -std::numeric_limits<T>::infinity();
- return true;
- }
- else
- {
- return false;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** 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_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 */
- TAG_SET = 4, /**< !!set Unordered set of non-equal values. @see https://yaml.org/type/set.html */
- TAG_SEQ = 5, /**< !!seq Sequence of arbitrary values. @see https://yaml.org/type/seq.html */
- // scalar types
- TAG_BINARY = 6, /**< !!binary A sequence of zero or more octets (8 bit values). @see https://yaml.org/type/binary.html */
- TAG_BOOL = 7, /**< !!bool Mathematical Booleans. @see https://yaml.org/type/bool.html */
- TAG_FLOAT = 8, /**< !!float Floating-point approximation to real numbers. https://yaml.org/type/float.html */
- TAG_INT = 9, /**< !!float Mathematical integers. https://yaml.org/type/int.html */
- TAG_MERGE = 10, /**< !!merge Specify one or more mapping to be merged with the current one. https://yaml.org/type/merge.html */
- TAG_NULL = 11, /**< !!null Devoid of value. https://yaml.org/type/null.html */
- TAG_STR = 12, /**< !!str A sequence of zero or more Unicode characters. https://yaml.org/type/str.html */
- TAG_TIMESTAMP = 13, /**< !!timestamp A point in time https://yaml.org/type/timestamp.html */
- TAG_VALUE = 14, /**< !!value Specify the default value of a mapping https://yaml.org/type/value.html */
- TAG_YAML = 15, /**< !!yaml Specify the default value of a mapping https://yaml.org/type/yaml.html */
-} YamlTag_e;
-
-YamlTag_e to_tag(csubstr tag);
-csubstr from_tag(YamlTag_e tag);
-csubstr from_tag_long(YamlTag_e tag);
-csubstr normalize_tag(csubstr tag);
-csubstr normalize_tag_long(csubstr tag);
-
-struct TagDirective
-{
- /** Eg `!e!` in `%TAG !e! tag:example.com,2000:app/` */
- csubstr handle;
- /** Eg `tag:example.com,2000:app/` in `%TAG !e! tag:example.com,2000:app/` */
- csubstr prefix;
- /** The next node to which this tag directive applies */
- size_t next_node_id;
-};
-
-#ifndef RYML_MAX_TAG_DIRECTIVES
-/** the maximum number of tag directives in a Tree */
-#define RYML_MAX_TAG_DIRECTIVES 4
-#endif
-
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-
-/** the integral type necessary to cover all the bits marking node types */
-using type_bits = uint64_t;
-
-
-/** a bit mask for marking node types */
-typedef enum : type_bits {
- // a convenience define, undefined below
- #define c4bit(v) (type_bits(1) << v)
- NOTYPE = 0, ///< no node type is set
- VAL = c4bit(0), ///< a leaf node, has a (possibly empty) value
- KEY = c4bit(1), ///< is member of a map, must have non-empty key
- MAP = c4bit(2), ///< a map: a parent of keyvals
- SEQ = c4bit(3), ///< a seq: a parent of vals
- DOC = c4bit(4), ///< a document
- STREAM = c4bit(5)|SEQ, ///< a stream: a seq of docs
- KEYREF = c4bit(6), ///< a *reference: the key references an &anchor
- VALREF = c4bit(7), ///< a *reference: the val references an &anchor
- KEYANCH = c4bit(8), ///< the key has an &anchor
- VALANCH = c4bit(9), ///< the val has an &anchor
- KEYTAG = c4bit(10), ///< the key has an explicit tag/type
- VALTAG = c4bit(11), ///< the val has an explicit tag/type
- _TYMASK = c4bit(12)-1, // all the bits up to here
- VALQUO = c4bit(12), ///< the val is quoted by '', "", > or |
- KEYQUO = c4bit(13), ///< the key is quoted by '', "", > or |
- KEYVAL = KEY|VAL,
- KEYSEQ = KEY|SEQ,
- KEYMAP = KEY|MAP,
- DOCMAP = DOC|MAP,
- DOCSEQ = DOC|SEQ,
- DOCVAL = DOC|VAL,
- _KEYMASK = KEY | KEYQUO | KEYANCH | KEYREF | KEYTAG,
- _VALMASK = VAL | VALQUO | VALANCH | VALREF | VALTAG,
- // these flags are from a work in progress and should not be used yet
- _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 >
- _WIP_VAL_FOLDED = c4bit(20), ///< mark val scalar as multiline, block folded >
- _WIP_KEY_SQUO = c4bit(21), ///< mark key scalar as single quoted
- _WIP_VAL_SQUO = c4bit(22), ///< mark val scalar as single quoted
- _WIP_KEY_DQUO = c4bit(23), ///< mark key scalar as double quoted
- _WIP_VAL_DQUO = c4bit(24), ///< mark val scalar as double quoted
- _WIP_KEY_PLAIN = c4bit(25), ///< mark key scalar as plain scalar (unquoted, even when multiline)
- _WIP_VAL_PLAIN = c4bit(26), ///< mark val scalar as plain scalar (unquoted, even when multiline)
- _WIP_KEY_STYLE = _WIP_KEY_LITERAL|_WIP_KEY_FOLDED|_WIP_KEY_SQUO|_WIP_KEY_DQUO|_WIP_KEY_PLAIN,
- _WIP_VAL_STYLE = _WIP_VAL_LITERAL|_WIP_VAL_FOLDED|_WIP_VAL_SQUO|_WIP_VAL_DQUO|_WIP_VAL_PLAIN,
- _WIP_KEY_FT_NL = c4bit(27), ///< features: mark key scalar as having \n in its contents
- _WIP_VAL_FT_NL = c4bit(28), ///< features: mark val scalar as having \n in its contents
- _WIP_KEY_FT_SQ = c4bit(29), ///< features: mark key scalar as having single quotes in its contents
- _WIP_VAL_FT_SQ = c4bit(30), ///< features: mark val scalar as having single quotes in its contents
- _WIP_KEY_FT_DQ = c4bit(31), ///< features: mark key scalar as having double quotes in its contents
- _WIP_VAL_FT_DQ = c4bit(32), ///< features: mark val scalar as having double quotes in its contents
- #undef c4bit
-} NodeType_e;
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** wraps a NodeType_e element with some syntactic sugar and predicates */
-struct NodeType
-{
-public:
-
- NodeType_e type;
-
-public:
-
- C4_ALWAYS_INLINE NodeType() : type(NOTYPE) {}
- C4_ALWAYS_INLINE NodeType(NodeType_e t) : type(t) {}
- C4_ALWAYS_INLINE NodeType(type_bits t) : type((NodeType_e)t) {}
-
- C4_ALWAYS_INLINE const char *type_str() const { return type_str(type); }
- static const char* type_str(NodeType_e t);
-
- C4_ALWAYS_INLINE void set(NodeType_e t) { type = t; }
- C4_ALWAYS_INLINE void set(type_bits t) { type = (NodeType_e)t; }
-
- C4_ALWAYS_INLINE void add(NodeType_e t) { type = (NodeType_e)(type|t); }
- C4_ALWAYS_INLINE void add(type_bits t) { type = (NodeType_e)(type|t); }
-
- C4_ALWAYS_INLINE void rem(NodeType_e t) { type = (NodeType_e)(type & ~t); }
- C4_ALWAYS_INLINE void rem(type_bits t) { type = (NodeType_e)(type & ~t); }
-
- C4_ALWAYS_INLINE void clear() { type = NOTYPE; }
-
-public:
-
- C4_ALWAYS_INLINE operator NodeType_e & C4_RESTRICT () { return type; }
- C4_ALWAYS_INLINE operator NodeType_e const& C4_RESTRICT () const { return type; }
-
- C4_ALWAYS_INLINE bool operator== (NodeType_e t) const { return type == t; }
- C4_ALWAYS_INLINE bool operator!= (NodeType_e t) const { return type != t; }
-
-public:
-
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Wnull-dereference"
- #elif defined(__GNUC__)
- # pragma GCC diagnostic push
- # if __GNUC__ >= 6
- # pragma GCC diagnostic ignored "-Wnull-dereference"
- # endif
- #endif
-
- C4_ALWAYS_INLINE bool is_notype() const { return type == NOTYPE; }
- C4_ALWAYS_INLINE bool is_stream() const { return ((type & STREAM) == STREAM) != 0; }
- C4_ALWAYS_INLINE bool is_doc() const { return (type & DOC) != 0; }
- C4_ALWAYS_INLINE bool is_container() const { return (type & (MAP|SEQ|STREAM)) != 0; }
- C4_ALWAYS_INLINE bool is_map() const { return (type & MAP) != 0; }
- C4_ALWAYS_INLINE bool is_seq() const { return (type & SEQ) != 0; }
- C4_ALWAYS_INLINE bool has_key() const { return (type & KEY) != 0; }
- C4_ALWAYS_INLINE bool has_val() const { return (type & VAL) != 0; }
- C4_ALWAYS_INLINE bool is_val() const { return (type & KEYVAL) == VAL; }
- C4_ALWAYS_INLINE bool is_keyval() const { return (type & KEYVAL) == KEYVAL; }
- C4_ALWAYS_INLINE bool has_key_tag() const { return (type & (KEY|KEYTAG)) == (KEY|KEYTAG); }
- C4_ALWAYS_INLINE bool has_val_tag() const { return ((type & VALTAG) && (type & (VAL|MAP|SEQ))); }
- C4_ALWAYS_INLINE bool has_key_anchor() const { return (type & (KEY|KEYANCH)) == (KEY|KEYANCH); }
- C4_ALWAYS_INLINE bool is_key_anchor() const { return (type & (KEY|KEYANCH)) == (KEY|KEYANCH); }
- C4_ALWAYS_INLINE bool has_val_anchor() const { return (type & VALANCH) != 0 && (type & (VAL|SEQ|MAP)) != 0; }
- C4_ALWAYS_INLINE bool is_val_anchor() const { return (type & VALANCH) != 0 && (type & (VAL|SEQ|MAP)) != 0; }
- C4_ALWAYS_INLINE bool has_anchor() const { return (type & (KEYANCH|VALANCH)) != 0; }
- C4_ALWAYS_INLINE bool is_anchor() const { return (type & (KEYANCH|VALANCH)) != 0; }
- C4_ALWAYS_INLINE bool is_key_ref() const { return (type & KEYREF) != 0; }
- C4_ALWAYS_INLINE bool is_val_ref() const { return (type & VALREF) != 0; }
- C4_ALWAYS_INLINE bool is_ref() const { return (type & (KEYREF|VALREF)) != 0; }
- C4_ALWAYS_INLINE bool is_anchor_or_ref() const { return (type & (KEYANCH|VALANCH|KEYREF|VALREF)) != 0; }
- C4_ALWAYS_INLINE bool is_key_quoted() const { return (type & (KEY|KEYQUO)) == (KEY|KEYQUO); }
- C4_ALWAYS_INLINE bool is_val_quoted() const { return (type & (VAL|VALQUO)) == (VAL|VALQUO); }
- C4_ALWAYS_INLINE bool is_quoted() const { return (type & (KEY|KEYQUO)) == (KEY|KEYQUO) || (type & (VAL|VALQUO)) == (VAL|VALQUO); }
-
- // these predicates are a work in progress and subject to change. Don't use yet.
- C4_ALWAYS_INLINE bool default_block() const { return (type & (_WIP_STYLE_BLOCK|_WIP_STYLE_FLOW_ML|_WIP_STYLE_FLOW_SL)) == 0; }
- C4_ALWAYS_INLINE bool marked_block() const { return (type & (_WIP_STYLE_BLOCK)) != 0; }
- C4_ALWAYS_INLINE bool marked_flow_sl() const { return (type & (_WIP_STYLE_FLOW_SL)) != 0; }
- C4_ALWAYS_INLINE bool marked_flow_ml() const { return (type & (_WIP_STYLE_FLOW_ML)) != 0; }
- C4_ALWAYS_INLINE bool marked_flow() const { return (type & (_WIP_STYLE_FLOW_ML|_WIP_STYLE_FLOW_SL)) != 0; }
- C4_ALWAYS_INLINE bool key_marked_literal() const { return (type & (_WIP_KEY_LITERAL)) != 0; }
- C4_ALWAYS_INLINE bool val_marked_literal() const { return (type & (_WIP_VAL_LITERAL)) != 0; }
- C4_ALWAYS_INLINE bool key_marked_folded() const { return (type & (_WIP_KEY_FOLDED)) != 0; }
- C4_ALWAYS_INLINE bool val_marked_folded() const { return (type & (_WIP_VAL_FOLDED)) != 0; }
- C4_ALWAYS_INLINE bool key_marked_squo() const { return (type & (_WIP_KEY_SQUO)) != 0; }
- C4_ALWAYS_INLINE bool val_marked_squo() const { return (type & (_WIP_VAL_SQUO)) != 0; }
- C4_ALWAYS_INLINE bool key_marked_dquo() const { return (type & (_WIP_KEY_DQUO)) != 0; }
- C4_ALWAYS_INLINE bool val_marked_dquo() const { return (type & (_WIP_VAL_DQUO)) != 0; }
- C4_ALWAYS_INLINE bool key_marked_plain() const { return (type & (_WIP_KEY_PLAIN)) != 0; }
- C4_ALWAYS_INLINE bool val_marked_plain() const { return (type & (_WIP_VAL_PLAIN)) != 0; }
-
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #elif defined(__GNUC__)
- # pragma GCC diagnostic pop
- #endif
-
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** a node scalar is a csubstr, which may be tagged and anchored. */
-struct NodeScalar
-{
- csubstr tag;
- csubstr scalar;
- csubstr anchor;
-
-public:
-
- /// initialize as an empty scalar
- inline NodeScalar() noexcept : tag(), scalar(), anchor() {}
-
- /// initialize as an untagged scalar
- template<size_t N>
- inline NodeScalar(const char (&s)[N]) noexcept : tag(), scalar(s), anchor() {}
- inline NodeScalar(csubstr s ) noexcept : tag(), scalar(s), anchor() {}
-
- /// initialize as a tagged scalar
- template<size_t N, size_t M>
- inline NodeScalar(const char (&t)[N], const char (&s)[N]) noexcept : tag(t), scalar(s), anchor() {}
- inline NodeScalar(csubstr t , csubstr s ) noexcept : tag(t), scalar(s), anchor() {}
-
-public:
-
- ~NodeScalar() noexcept = default;
- NodeScalar(NodeScalar &&) noexcept = default;
- NodeScalar(NodeScalar const&) noexcept = default;
- NodeScalar& operator= (NodeScalar &&) noexcept = default;
- NodeScalar& operator= (NodeScalar const&) noexcept = default;
-
-public:
-
- bool empty() const noexcept { return tag.empty() && scalar.empty() && anchor.empty(); }
-
- void clear() noexcept { tag.clear(); scalar.clear(); anchor.clear(); }
-
- void set_ref_maybe_replacing_scalar(csubstr ref, bool has_scalar) noexcept
- {
- csubstr trimmed = ref.begins_with('*') ? ref.sub(1) : ref;
- anchor = trimmed;
- if((!has_scalar) || !scalar.ends_with(trimmed))
- scalar = ref;
- }
-};
-C4_MUST_BE_TRIVIAL_COPY(NodeScalar);
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** convenience class to initialize nodes */
-struct NodeInit
-{
-
- NodeType type;
- NodeScalar key;
- NodeScalar val;
-
-public:
-
- /// initialize as an empty node
- NodeInit() : type(NOTYPE), key(), val() {}
- /// initialize as a typed node
- NodeInit(NodeType_e t) : type(t), key(), val() {}
- /// initialize as a sequence member
- NodeInit(NodeScalar const& v) : type(VAL), key(), val(v) { _add_flags(); }
- /// initialize as a mapping member
- NodeInit( NodeScalar const& k, NodeScalar const& v) : type(KEYVAL), key(k.tag, k.scalar), val(v.tag, v.scalar) { _add_flags(); }
- /// initialize as a mapping member with explicit type
- NodeInit(NodeType_e t, NodeScalar const& k, NodeScalar const& v) : type(t ), key(k.tag, k.scalar), val(v.tag, v.scalar) { _add_flags(); }
- /// initialize as a mapping member with explicit type (eg SEQ or MAP)
- NodeInit(NodeType_e t, NodeScalar const& k ) : type(t ), key(k.tag, k.scalar), val( ) { _add_flags(KEY); }
-
-public:
-
- void clear()
- {
- type.clear();
- key.clear();
- val.clear();
- }
-
- void _add_flags(type_bits more_flags=0)
- {
- type = (type|more_flags);
- if( ! key.tag.empty())
- type = (type|KEYTAG);
- if( ! val.tag.empty())
- type = (type|VALTAG);
- if( ! key.anchor.empty())
- type = (type|KEYANCH);
- if( ! val.anchor.empty())
- type = (type|VALANCH);
- }
-
- bool _check() const
- {
- // key cannot be empty
- RYML_ASSERT(key.scalar.empty() == ((type & KEY) == 0));
- // key tag cannot be empty
- RYML_ASSERT(key.tag.empty() == ((type & KEYTAG) == 0));
- // val may be empty even though VAL is set. But when VAL is not set, val must be empty
- RYML_ASSERT(((type & VAL) != 0) || val.scalar.empty());
- // val tag cannot be empty
- RYML_ASSERT(val.tag.empty() == ((type & VALTAG) == 0));
- return true;
- }
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-/** contains the data for each YAML node. */
-struct NodeData
-{
- NodeType m_type;
-
- NodeScalar m_key;
- NodeScalar m_val;
-
- size_t m_parent;
- size_t m_first_child;
- size_t m_last_child;
- size_t m_next_sibling;
- size_t m_prev_sibling;
-};
-C4_MUST_BE_TRIVIAL_COPY(NodeData);
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-class RYML_EXPORT Tree
-{
-public:
-
- /** @name construction and assignment */
- /** @{ */
-
- Tree() : Tree(get_callbacks()) {}
- Tree(Callbacks const& cb);
- Tree(size_t node_capacity, size_t arena_capacity=0) : Tree(node_capacity, arena_capacity, get_callbacks()) {}
- Tree(size_t node_capacity, size_t arena_capacity, Callbacks const& cb);
-
- ~Tree();
-
- Tree(Tree const& that) noexcept;
- Tree(Tree && that) noexcept;
-
- Tree& operator= (Tree const& that) noexcept;
- Tree& operator= (Tree && that) noexcept;
-
- /** @} */
-
-public:
-
- /** @name memory and sizing */
- /** @{ */
-
- void reserve(size_t node_capacity);
-
- /** clear the tree and zero every node
- * @note does NOT clear the arena
- * @see clear_arena() */
- void clear();
- inline void clear_arena() { m_arena_pos = 0; }
-
- inline bool empty() const { return m_size == 0; }
-
- inline size_t size() const { return m_size; }
- inline size_t capacity() const { return m_cap; }
- inline size_t slack() const { RYML_ASSERT(m_cap >= m_size); return m_cap - m_size; }
-
- Callbacks const& callbacks() const { return m_callbacks; }
- void callbacks(Callbacks const& cb) { m_callbacks = cb; }
-
- /** @} */
-
-public:
-
- /** @name node getters */
- /** @{ */
-
- //! get the index of a node belonging to this tree.
- //! @p n can be nullptr, in which case a
- size_t id(NodeData const* n) const
- {
- if( ! n)
- {
- return NONE;
- }
- RYML_ASSERT(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)
- {
- if(i == NONE)
- return nullptr;
- RYML_ASSERT(i >= 0 && i < m_cap);
- return m_buf + i;
- }
- //! 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
- {
- if(i == NONE)
- return nullptr;
- RYML_ASSERT(i >= 0 && i < m_cap);
- return m_buf + i;
- }
-
- //! 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_ASSERT(i != NONE && i >= 0 && i < m_cap); return m_buf + i; }
- //! 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_ASSERT(i != NONE && i >= 0 && i < m_cap); return m_buf + i; }
-
- //! Get the id of the root node
- size_t root_id() { if(m_cap == 0) { reserve(16); } RYML_ASSERT(m_cap > 0 && m_size > 0); return 0; }
- //! Get the id of the root node
- size_t root_id() const { RYML_ASSERT(m_cap > 0 && m_size > 0); return 0; }
-
- //! Get a NodeRef of a node by id
- NodeRef ref(size_t id);
- //! Get a NodeRef of a node by id
- ConstNodeRef ref(size_t id) const;
- //! Get a NodeRef of a node by id
- ConstNodeRef cref(size_t id);
- //! Get a NodeRef of a node by id
- ConstNodeRef cref(size_t id) const;
-
- //! Get the root as a NodeRef
- NodeRef rootref();
- //! Get the root as a NodeRef
- ConstNodeRef rootref() const;
- //! Get the root as a NodeRef
- ConstNodeRef crootref();
- //! Get the root as a NodeRef
- ConstNodeRef crootref() const;
-
- //! find a root child by name, return it as a NodeRef
- //! @note requires the root to be a map.
- NodeRef operator[] (csubstr key);
- //! find a root child by name, return it as a NodeRef
- //! @note requires the root to be a map.
- 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
- 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
- ConstNodeRef operator[] (size_t i) const;
-
- //! get the i-th document of the stream
- //! @note @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
- ConstNodeRef docref(size_t i) const;
-
- /** @} */
-
-public:
-
- /** @name node property getters */
- /** @{ */
-
- NodeType type(size_t node) const { return _p(node)->m_type; }
- const char* type_str(size_t node) const { return NodeType::type_str(_p(node)->m_type); }
-
- csubstr const& key (size_t node) const { RYML_ASSERT(has_key(node)); return _p(node)->m_key.scalar; }
- csubstr const& key_tag (size_t node) const { RYML_ASSERT(has_key_tag(node)); return _p(node)->m_key.tag; }
- csubstr const& key_ref (size_t node) const { RYML_ASSERT(is_key_ref(node) && ! has_key_anchor(node)); return _p(node)->m_key.anchor; }
- csubstr const& key_anchor(size_t node) const { RYML_ASSERT( ! is_key_ref(node) && has_key_anchor(node)); return _p(node)->m_key.anchor; }
- NodeScalar const& keysc (size_t node) const { RYML_ASSERT(has_key(node)); return _p(node)->m_key; }
-
- csubstr const& val (size_t node) const { RYML_ASSERT(has_val(node)); return _p(node)->m_val.scalar; }
- csubstr const& val_tag (size_t node) const { RYML_ASSERT(has_val_tag(node)); return _p(node)->m_val.tag; }
- csubstr const& val_ref (size_t node) const { RYML_ASSERT(is_val_ref(node) && ! has_val_anchor(node)); return _p(node)->m_val.anchor; }
- csubstr const& val_anchor(size_t node) const { RYML_ASSERT( ! is_val_ref(node) && has_val_anchor(node)); return _p(node)->m_val.anchor; }
- NodeScalar const& valsc (size_t node) const { RYML_ASSERT(has_val(node)); return _p(node)->m_val; }
-
- /** @} */
-
-public:
-
- /** @name node predicates */
- /** @{ */
-
- C4_ALWAYS_INLINE bool is_stream(size_t node) const { return _p(node)->m_type.is_stream(); }
- C4_ALWAYS_INLINE bool is_doc(size_t node) const { return _p(node)->m_type.is_doc(); }
- C4_ALWAYS_INLINE bool is_container(size_t node) const { return _p(node)->m_type.is_container(); }
- C4_ALWAYS_INLINE bool is_map(size_t node) const { return _p(node)->m_type.is_map(); }
- C4_ALWAYS_INLINE bool is_seq(size_t node) const { return _p(node)->m_type.is_seq(); }
- C4_ALWAYS_INLINE bool has_key(size_t node) const { return _p(node)->m_type.has_key(); }
- C4_ALWAYS_INLINE bool has_val(size_t node) const { return _p(node)->m_type.has_val(); }
- C4_ALWAYS_INLINE bool is_val(size_t node) const { return _p(node)->m_type.is_val(); }
- C4_ALWAYS_INLINE bool is_keyval(size_t node) const { return _p(node)->m_type.is_keyval(); }
- C4_ALWAYS_INLINE bool has_key_tag(size_t node) const { return _p(node)->m_type.has_key_tag(); }
- C4_ALWAYS_INLINE bool has_val_tag(size_t node) const { return _p(node)->m_type.has_val_tag(); }
- C4_ALWAYS_INLINE bool has_key_anchor(size_t node) const { return _p(node)->m_type.has_key_anchor(); }
- C4_ALWAYS_INLINE bool is_key_anchor(size_t node) const { return _p(node)->m_type.is_key_anchor(); }
- C4_ALWAYS_INLINE bool has_val_anchor(size_t node) const { return _p(node)->m_type.has_val_anchor(); }
- C4_ALWAYS_INLINE bool is_val_anchor(size_t node) const { return _p(node)->m_type.is_val_anchor(); }
- C4_ALWAYS_INLINE bool has_anchor(size_t node) const { return _p(node)->m_type.has_anchor(); }
- C4_ALWAYS_INLINE bool is_anchor(size_t node) const { return _p(node)->m_type.is_anchor(); }
- C4_ALWAYS_INLINE bool is_key_ref(size_t node) const { return _p(node)->m_type.is_key_ref(); }
- C4_ALWAYS_INLINE bool is_val_ref(size_t node) const { return _p(node)->m_type.is_val_ref(); }
- C4_ALWAYS_INLINE bool is_ref(size_t node) const { return _p(node)->m_type.is_ref(); }
- C4_ALWAYS_INLINE bool is_anchor_or_ref(size_t node) const { return _p(node)->m_type.is_anchor_or_ref(); }
- C4_ALWAYS_INLINE bool is_key_quoted(size_t node) const { return _p(node)->m_type.is_key_quoted(); }
- C4_ALWAYS_INLINE bool is_val_quoted(size_t node) const { return _p(node)->m_type.is_val_quoted(); }
- C4_ALWAYS_INLINE bool is_quoted(size_t node) const { return _p(node)->m_type.is_quoted(); }
-
- C4_ALWAYS_INLINE bool parent_is_seq(size_t node) const { RYML_ASSERT(has_parent(node)); return is_seq(_p(node)->m_parent); }
- C4_ALWAYS_INLINE bool parent_is_map(size_t node) const { RYML_ASSERT(has_parent(node)); return is_map(_p(node)->m_parent); }
-
- /** true when key and val are empty, and has no children */
- C4_ALWAYS_INLINE bool empty(size_t node) const { return ! has_children(node) && _p(node)->m_key.empty() && (( ! (_p(node)->m_type & VAL)) || _p(node)->m_val.empty()); }
- /** true when the node has an anchor named a */
- C4_ALWAYS_INLINE bool has_anchor(size_t node, csubstr a) const { return _p(node)->m_key.anchor == a || _p(node)->m_val.anchor == a; }
-
- C4_ALWAYS_INLINE bool key_is_null(size_t node) const { RYML_ASSERT(has_key(node)); NodeData const* C4_RESTRICT n = _p(node); return !n->m_type.is_key_quoted() && _is_null(n->m_key.scalar); }
- C4_ALWAYS_INLINE bool val_is_null(size_t node) const { RYML_ASSERT(has_val(node)); NodeData const* C4_RESTRICT n = _p(node); return !n->m_type.is_val_quoted() && _is_null(n->m_val.scalar); }
- static bool _is_null(csubstr s) noexcept
- {
- return s.str == nullptr ||
- s == "~" ||
- s == "null" ||
- s == "Null" ||
- s == "NULL";
- }
-
- /** @} */
-
-public:
-
- /** @name hierarchy predicates */
- /** @{ */
-
- bool is_root(size_t node) const { RYML_ASSERT(_p(node)->m_parent != NONE || node == 0); return _p(node)->m_parent == NONE; }
-
- bool has_parent(size_t node) const { return _p(node)->m_parent != NONE; }
-
- /** true if @p node has a child with id @p ch */
- bool has_child(size_t node, size_t ch) const { return _p(ch)->m_parent == node; }
- /** true if @p node has a child with key @p key */
- bool has_child(size_t node, csubstr key) const { return find_child(node, key) != npos; }
- /** true if @p node has any children key */
- bool has_children(size_t node) const { return _p(node)->m_first_child != NONE; }
-
- /** true if @p node has a sibling with id @p sib */
- bool has_sibling(size_t node, size_t sib) const { return _p(node)->m_parent == _p(sib)->m_parent; }
- /** true if one of the node's siblings has the given key */
- bool has_sibling(size_t node, csubstr key) const { return find_sibling(node, key) != npos; }
- /** true if node is not a single child */
- bool has_other_siblings(size_t node) const
- {
- NodeData const *n = _p(node);
- if(C4_LIKELY(n->m_parent != NONE))
- {
- n = _p(n->m_parent);
- return n->m_first_child != n->m_last_child;
- }
- return false;
- }
-
- RYML_DEPRECATED("use has_other_siblings()") bool has_siblings(size_t /*node*/) const { return true; }
-
- /** @} */
-
-public:
-
- /** @name hierarchy getters */
- /** @{ */
-
- size_t parent(size_t node) const { return _p(node)->m_parent; }
-
- size_t prev_sibling(size_t node) const { return _p(node)->m_prev_sibling; }
- size_t next_sibling(size_t node) const { return _p(node)->m_next_sibling; }
-
- /** O(#num_children) */
- size_t num_children(size_t node) const;
- size_t child_pos(size_t node, size_t ch) const;
- size_t first_child(size_t node) const { return _p(node)->m_first_child; }
- size_t last_child(size_t node) const { return _p(node)->m_last_child; }
- size_t child(size_t node, size_t pos) const;
- size_t find_child(size_t node, csubstr const& key) const;
-
- /** O(#num_siblings) */
- /** counts with this */
- size_t num_siblings(size_t node) const { return is_root(node) ? 1 : num_children(_p(node)->m_parent); }
- /** does not count with this */
- size_t num_other_siblings(size_t node) const { size_t ns = num_siblings(node); RYML_ASSERT(ns > 0); return ns-1; }
- size_t sibling_pos(size_t node, size_t sib) const { RYML_ASSERT( ! is_root(node) || node == root_id()); return child_pos(_p(node)->m_parent, sib); }
- size_t first_sibling(size_t node) const { return is_root(node) ? node : _p(_p(node)->m_parent)->m_first_child; }
- size_t last_sibling(size_t node) const { return is_root(node) ? node : _p(_p(node)->m_parent)->m_last_child; }
- size_t sibling(size_t node, size_t pos) const { return child(_p(node)->m_parent, pos); }
- size_t find_sibling(size_t node, csubstr const& key) const { return find_child(_p(node)->m_parent, key); }
-
- size_t doc(size_t i) const { size_t rid = root_id(); RYML_ASSERT(is_stream(rid)); return child(rid, i); } //!< gets the @p i document node index. requires that the root node is a stream.
-
- /** @} */
-
-public:
-
- /** @name node modifiers */
- /** @{ */
-
- void to_keyval(size_t node, csubstr key, csubstr val, type_bits more_flags=0);
- void to_map(size_t node, csubstr key, type_bits more_flags=0);
- void to_seq(size_t node, csubstr key, type_bits more_flags=0);
- void to_val(size_t node, csubstr val, type_bits more_flags=0);
- void to_map(size_t node, type_bits more_flags=0);
- void to_seq(size_t node, type_bits more_flags=0);
- void to_doc(size_t node, type_bits more_flags=0);
- void to_stream(size_t node, type_bits more_flags=0);
-
- void set_key(size_t node, csubstr key) { RYML_ASSERT(has_key(node)); _p(node)->m_key.scalar = key; }
- void set_val(size_t node, csubstr val) { RYML_ASSERT(has_val(node)); _p(node)->m_val.scalar = val; }
-
- void set_key_tag(size_t node, csubstr tag) { RYML_ASSERT(has_key(node)); _p(node)->m_key.tag = tag; _add_flags(node, KEYTAG); }
- void set_val_tag(size_t node, csubstr tag) { RYML_ASSERT(has_val(node) || is_container(node)); _p(node)->m_val.tag = tag; _add_flags(node, VALTAG); }
-
- void set_key_anchor(size_t node, csubstr anchor) { RYML_ASSERT( ! is_key_ref(node)); _p(node)->m_key.anchor = anchor.triml('&'); _add_flags(node, KEYANCH); }
- void set_val_anchor(size_t node, csubstr anchor) { RYML_ASSERT( ! is_val_ref(node)); _p(node)->m_val.anchor = anchor.triml('&'); _add_flags(node, VALANCH); }
- void set_key_ref (size_t node, csubstr ref ) { RYML_ASSERT( ! has_key_anchor(node)); NodeData* C4_RESTRICT n = _p(node); n->m_key.set_ref_maybe_replacing_scalar(ref, n->m_type.has_key()); _add_flags(node, KEY|KEYREF); }
- void set_val_ref (size_t node, csubstr ref ) { RYML_ASSERT( ! has_val_anchor(node)); NodeData* C4_RESTRICT n = _p(node); n->m_val.set_ref_maybe_replacing_scalar(ref, n->m_type.has_val()); _add_flags(node, VAL|VALREF); }
-
- void rem_key_anchor(size_t node) { _p(node)->m_key.anchor.clear(); _rem_flags(node, KEYANCH); }
- void rem_val_anchor(size_t node) { _p(node)->m_val.anchor.clear(); _rem_flags(node, VALANCH); }
- void rem_key_ref (size_t node) { _p(node)->m_key.anchor.clear(); _rem_flags(node, KEYREF); }
- void rem_val_ref (size_t node) { _p(node)->m_val.anchor.clear(); _rem_flags(node, VALREF); }
- void rem_anchor_ref(size_t node) { _p(node)->m_key.anchor.clear(); _p(node)->m_val.anchor.clear(); _rem_flags(node, KEYANCH|VALANCH|KEYREF|VALREF); }
-
- /** @} */
-
-public:
-
- /** @name tree modifiers */
- /** @{ */
-
- /** reorder the tree in memory so that all the nodes are stored
- * in a linear sequence when visited in depth-first order.
- * This will invalidate existing ids, since the node id is its
- * position in the node array. */
- void reorder();
-
- /** Resolve references (aliases <- anchors) in the tree.
- *
- * Dereferencing is opt-in; after parsing, Tree::resolve()
- * has to be called explicitly for obtaining resolved references in the
- * tree. This method will resolve all references and substitute the
- * anchored values in place of the reference.
- *
- * This method first does a full traversal of the tree to gather all
- * anchors and references in a separate collection, then it goes through
- * that collection to locate the names, which it does by obeying the YAML
- * standard diktat that "an alias node refers to the most recent node in
- * the serialization having the specified anchor"
- *
- * So, depending on the number of anchor/alias nodes, this is a
- * potentially expensive operation, with a best-case linear complexity
- * (from the initial traversal). This potential cost is the reason for
- * requiring an explicit call.
- */
- void resolve();
-
- /** @} */
-
-public:
-
- /** @name tag directives */
- /** @{ */
-
- void resolve_tags();
-
- size_t num_tag_directives() const;
- size_t add_tag_directive(TagDirective const& td);
- void clear_tag_directives();
-
- size_t resolve_tag(substr output, csubstr tag, size_t node_id) const;
- csubstr resolve_tag_sub(substr output, csubstr tag, size_t node_id) const
- {
- size_t needed = resolve_tag(output, tag, node_id);
- return needed <= output.len ? output.first(needed) : output;
- }
-
- using tag_directive_const_iterator = TagDirective const*;
- tag_directive_const_iterator begin_tag_directives() const { return m_tag_directives; }
- tag_directive_const_iterator end_tag_directives() const { return m_tag_directives + num_tag_directives(); }
-
- struct TagDirectiveProxy
- {
- tag_directive_const_iterator b, e;
- tag_directive_const_iterator begin() const { return b; }
- tag_directive_const_iterator end() const { return e; }
- };
-
- TagDirectiveProxy tag_directives() const { return TagDirectiveProxy{begin_tag_directives(), end_tag_directives()}; }
-
- /** @} */
-
-public:
-
- /** @name modifying hierarchy */
- /** @{ */
-
- /** create and insert a new child of @p parent. insert after the (to-be)
- * sibling @p after, which must be a child of @p parent. To insert as the
- * first child, set after to NONE */
- C4_ALWAYS_INLINE size_t insert_child(size_t parent, size_t after)
- {
- RYML_ASSERT(parent != NONE);
- RYML_ASSERT(is_container(parent) || is_root(parent));
- RYML_ASSERT(after == NONE || (_p(after)->m_parent == parent));
- size_t child = _claim();
- _set_hierarchy(child, parent, after);
- return child;
- }
- /** create and insert a node as the first child of @p parent */
- C4_ALWAYS_INLINE size_t prepend_child(size_t parent) { return insert_child(parent, NONE); }
- /** create and insert a node as the last child of @p parent */
- C4_ALWAYS_INLINE size_t append_child(size_t parent) { return insert_child(parent, _p(parent)->m_last_child); }
-
-public:
-
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Wnull-dereference"
- #elif defined(__GNUC__)
- # pragma GCC diagnostic push
- # if __GNUC__ >= 6
- # pragma GCC diagnostic ignored "-Wnull-dereference"
- # endif
- #endif
-
- //! create and insert a new sibling of n. insert after "after"
- C4_ALWAYS_INLINE size_t insert_sibling(size_t node, size_t after)
- {
- return insert_child(_p(node)->m_parent, after);
- }
- /** create and insert a node as the first node of @p parent */
- C4_ALWAYS_INLINE size_t prepend_sibling(size_t node) { return prepend_child(_p(node)->m_parent); }
- C4_ALWAYS_INLINE size_t append_sibling(size_t node) { return append_child(_p(node)->m_parent); }
-
-public:
-
- /** remove an entire branch at once: ie remove the children and the node itself */
- inline void remove(size_t node)
- {
- remove_children(node);
- _release(node);
- }
-
- /** remove all the node's children, but keep the node itself */
- void remove_children(size_t node);
-
- /** change the @p type of the node to one of MAP, SEQ or VAL. @p
- * type must have one and only one of MAP,SEQ,VAL; @p type may
- * possibly have KEY, but if it does, then the @p node must also
- * have KEY. Changing to the same type is a no-op. Otherwise,
- * changing to a different type will initialize the node with an
- * empty value of the desired type: changing to VAL will
- * initialize with a null scalar (~), changing to MAP will
- * initialize with an empty map ({}), and changing to SEQ will
- * initialize with an empty seq ([]). */
- bool change_type(size_t node, NodeType type);
-
- bool change_type(size_t node, type_bits type)
- {
- return change_type(node, (NodeType)type);
- }
-
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #elif defined(__GNUC__)
- # pragma GCC diagnostic pop
- #endif
-
-public:
-
- /** change the node's position in the parent */
- void move(size_t node, size_t after);
-
- /** change the node's parent and position */
- void move(size_t node, size_t new_parent, size_t after);
-
- /** change the node's parent and position to a different tree
- * @return the index of the new node in the destination tree */
- size_t move(Tree * src, size_t node, size_t new_parent, size_t after);
-
- /** ensure the first node is a stream. Eg, change this tree
- *
- * DOCMAP
- * MAP
- * KEYVAL
- * KEYVAL
- * SEQ
- * VAL
- *
- * to
- *
- * STREAM
- * DOCMAP
- * MAP
- * KEYVAL
- * KEYVAL
- * SEQ
- * VAL
- *
- * If the root is already a stream, this is a no-op.
- */
- void set_root_as_stream();
-
-public:
-
- /** recursively duplicate a node from this tree into a new parent,
- * placing it after one of its children
- * @return the index of the copy */
- size_t duplicate(size_t node, size_t new_parent, size_t after);
- /** recursively duplicate a node from a different tree into a new parent,
- * placing it after one of its children
- * @return the index of the copy */
- size_t duplicate(Tree const* src, size_t node, size_t new_parent, size_t after);
-
- /** recursively duplicate the node's children (but not the node)
- * @return the index of the last duplicated child */
- size_t duplicate_children(size_t node, size_t parent, size_t after);
- /** recursively duplicate the node's children (but not the node), where
- * the node is from a different tree
- * @return the index of the last duplicated child */
- size_t duplicate_children(Tree const* src, size_t node, size_t parent, size_t after);
-
- void duplicate_contents(size_t node, size_t where);
- void duplicate_contents(Tree const* src, size_t node, size_t where);
-
- /** duplicate the node's children (but not the node) in a new parent, but
- * omit repetitions where a duplicated node has the same key (in maps) or
- * value (in seqs). If one of the duplicated children has the same key
- * (in maps) or value (in seqs) as one of the parent's children, the one
- * that is placed closest to the end will prevail. */
- size_t duplicate_children_no_rep(size_t node, size_t parent, size_t after);
- size_t duplicate_children_no_rep(Tree const* src, size_t node, size_t parent, size_t after);
-
-public:
-
- void merge_with(Tree const* src, size_t src_node=NONE, size_t dst_root=NONE);
-
- /** @} */
-
-public:
-
- /** @name internal string arena */
- /** @{ */
-
- /** get the current size of the tree's internal arena */
- RYML_DEPRECATED("use arena_size() instead") size_t arena_pos() const { return m_arena_pos; }
- /** get the current size of the tree's internal arena */
- inline size_t arena_size() const { return m_arena_pos; }
- /** get the current capacity of the tree's internal arena */
- inline size_t arena_capacity() const { return m_arena.len; }
- /** get the current slack of the tree's internal arena */
- inline size_t arena_slack() const { RYML_ASSERT(m_arena.len >= m_arena_pos); return m_arena.len - m_arena_pos; }
-
- /** get the current arena */
- substr arena() const { return m_arena.first(m_arena_pos); }
-
- /** return true if the given substring is part of the tree's string arena */
- bool in_arena(csubstr s) const
- {
- return m_arena.is_super(s);
- }
-
- /** serialize the given floating-point variable to the tree's
- * arena, growing it as needed to accomodate the serialization.
- *
- * @note Growing the arena may cause relocation of the entire
- * existing arena, and thus change the contents of individual
- * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this
- * cost, ensure that the arena is reserved to an appropriate size
- * using .reserve_arena()
- *
- * @see alloc_arena() */
- template<class T>
- typename std::enable_if<std::is_floating_point<T>::value, csubstr>::type
- to_arena(T const& C4_RESTRICT a)
- {
- substr rem(m_arena.sub(m_arena_pos));
- size_t num = to_chars_float(rem, a);
- if(num > rem.len)
- {
- rem = _grow_arena(num);
- num = to_chars_float(rem, a);
- RYML_ASSERT(num <= rem.len);
- }
- rem = _request_span(num);
- return rem;
- }
-
- /** serialize the given non-floating-point variable to the tree's
- * arena, growing it as needed to accomodate the serialization.
- *
- * @note Growing the arena may cause relocation of the entire
- * existing arena, and thus change the contents of individual
- * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this
- * cost, ensure that the arena is reserved to an appropriate size
- * using .reserve_arena()
- *
- * @see alloc_arena() */
- template<class T>
- typename std::enable_if<!std::is_floating_point<T>::value, csubstr>::type
- to_arena(T const& C4_RESTRICT a)
- {
- substr rem(m_arena.sub(m_arena_pos));
- size_t num = to_chars(rem, a);
- if(num > rem.len)
- {
- rem = _grow_arena(num);
- num = to_chars(rem, a);
- RYML_ASSERT(num <= rem.len);
- }
- rem = _request_span(num);
- return rem;
- }
-
- /** serialize the given csubstr to the tree's arena, growing the
- * arena as needed to accomodate the serialization.
- *
- * @note Growing the arena may cause relocation of the entire
- * existing arena, and thus change the contents of individual
- * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this
- * cost, ensure that the arena is reserved to an appropriate size
- * using .reserve_arena()
- *
- * @see alloc_arena() */
- csubstr to_arena(csubstr a)
- {
- if(a.len > 0)
- {
- substr rem(m_arena.sub(m_arena_pos));
- size_t num = to_chars(rem, a);
- if(num > rem.len)
- {
- rem = _grow_arena(num);
- num = to_chars(rem, a);
- RYML_ASSERT(num <= rem.len);
- }
- return _request_span(num);
- }
- else
- {
- if(a.str == nullptr)
- {
- return csubstr{};
- }
- else if(m_arena.str == nullptr)
- {
- // Arena is empty and we want to store a non-null
- // zero-length string.
- // Even though the string has zero length, we need
- // some "memory" to store a non-nullptr string
- _grow_arena(1);
- }
- return _request_span(0);
- }
- }
- C4_ALWAYS_INLINE csubstr to_arena(const char *s)
- {
- return to_arena(to_csubstr(s));
- }
- C4_ALWAYS_INLINE csubstr to_arena(std::nullptr_t)
- {
- return csubstr{};
- }
-
- /** copy the given substr to the tree's arena, growing it by the
- * required size
- *
- * @note Growing the arena may cause relocation of the entire
- * existing arena, and thus change the contents of individual
- * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this
- * cost, ensure that the arena is reserved to an appropriate size
- * using .reserve_arena()
- *
- * @see alloc_arena() */
- substr copy_to_arena(csubstr s)
- {
- substr cp = alloc_arena(s.len);
- RYML_ASSERT(cp.len == s.len);
- RYML_ASSERT(!s.overlaps(cp));
- #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10)
- C4_SUPPRESS_WARNING_GCC_PUSH
- C4_SUPPRESS_WARNING_GCC("-Wstringop-overflow=") // no need for terminating \0
- C4_SUPPRESS_WARNING_GCC( "-Wrestrict") // there's an assert to ensure no violation of restrict behavior
- #endif
- if(s.len)
- memcpy(cp.str, s.str, s.len);
- #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10)
- C4_SUPPRESS_WARNING_GCC_POP
- #endif
- return cp;
- }
-
- /** grow the tree's string arena by the given size and return a substr
- * of the added portion
- *
- * @note Growing the arena may cause relocation of the entire
- * existing arena, and thus change the contents of individual
- * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this
- * cost, ensure that the arena is reserved to an appropriate size
- * using .reserve_arena().
- *
- * @see reserve_arena() */
- substr alloc_arena(size_t sz)
- {
- if(sz > arena_slack())
- _grow_arena(sz - arena_slack());
- substr s = _request_span(sz);
- return s;
- }
-
- /** ensure the tree's internal string arena is at least the given capacity
- * @note This operation has a potential complexity of O(numNodes)+O(arenasize).
- * Growing the arena may cause relocation of the entire
- * existing arena, and thus change the contents of individual nodes. */
- void reserve_arena(size_t arena_cap)
- {
- if(arena_cap > m_arena.len)
- {
- substr buf;
- buf.str = (char*) m_callbacks.m_allocate(arena_cap, m_arena.str, m_callbacks.m_user_data);
- buf.len = arena_cap;
- if(m_arena.str)
- {
- RYML_ASSERT(m_arena.len >= 0);
- _relocate(buf); // does a memcpy and changes nodes using the arena
- m_callbacks.m_free(m_arena.str, m_arena.len, m_callbacks.m_user_data);
- }
- m_arena = buf;
- }
- }
-
- /** @} */
-
-private:
-
- substr _grow_arena(size_t more)
- {
- size_t cap = m_arena.len + more;
- cap = cap < 2 * m_arena.len ? 2 * m_arena.len : cap;
- cap = cap < 64 ? 64 : cap;
- reserve_arena(cap);
- return m_arena.sub(m_arena_pos);
- }
-
- substr _request_span(size_t sz)
- {
- substr s;
- s = m_arena.sub(m_arena_pos, sz);
- m_arena_pos += sz;
- return s;
- }
-
- substr _relocated(csubstr s, substr next_arena) const
- {
- RYML_ASSERT(m_arena.is_super(s));
- RYML_ASSERT(m_arena.sub(0, m_arena_pos).is_super(s));
- auto pos = (s.str - m_arena.str);
- substr r(next_arena.str + pos, s.len);
- RYML_ASSERT(r.str - next_arena.str == pos);
- RYML_ASSERT(next_arena.sub(0, m_arena_pos).is_super(r));
- return r;
- }
-
-public:
-
- /** @name lookup */
- /** @{ */
-
- struct lookup_result
- {
- size_t target;
- size_t closest;
- size_t path_pos;
- csubstr path;
-
- inline operator bool() const { return target != NONE; }
-
- lookup_result() : target(NONE), closest(NONE), path_pos(0), path() {}
- lookup_result(csubstr path_, size_t start) : target(NONE), closest(start), path_pos(0), path(path_) {}
-
- /** get the part ot the input path that was resolved */
- csubstr resolved() const;
- /** get the part ot the input path that was unresolved */
- csubstr unresolved() const;
- };
-
- /** for example foo.bar[0].baz */
- lookup_result lookup_path(csubstr path, size_t start=NONE) const;
-
- /** defaulted lookup: lookup @p path; if the lookup fails, recursively modify
- * the tree so that the corresponding lookup_path() would return the
- * default value.
- * @see lookup_path() */
- size_t lookup_path_or_modify(csubstr default_value, csubstr path, size_t start=NONE);
-
- /** defaulted lookup: lookup @p path; if the lookup fails, recursively modify
- * the tree so that the corresponding lookup_path() would return the
- * branch @p src_node (from the tree @p src).
- * @see lookup_path() */
- size_t lookup_path_or_modify(Tree const *src, size_t src_node, csubstr path, size_t start=NONE);
-
- /** @} */
-
-private:
-
- struct _lookup_path_token
- {
- csubstr value;
- NodeType type;
- _lookup_path_token() : value(), type() {}
- _lookup_path_token(csubstr v, NodeType t) : value(v), type(t) {}
- inline operator bool() const { return type != NOTYPE; }
- bool is_index() const { return value.begins_with('[') && value.ends_with(']'); }
- };
-
- size_t _lookup_path_or_create(csubstr path, size_t start);
-
- void _lookup_path (lookup_result *r) const;
- void _lookup_path_modify(lookup_result *r);
-
- size_t _next_node (lookup_result *r, _lookup_path_token *parent) const;
- size_t _next_node_modify(lookup_result *r, _lookup_path_token *parent);
-
- void _advance(lookup_result *r, size_t more) const;
-
- _lookup_path_token _next_token(lookup_result *r, _lookup_path_token const& parent) const;
-
-private:
-
- void _clear();
- void _free();
- void _copy(Tree const& that);
- void _move(Tree & that);
-
- void _relocate(substr next_arena);
-
-public:
-
- #if ! RYML_USE_ASSERT
- C4_ALWAYS_INLINE void _check_next_flags(size_t, type_bits) {}
- #else
- void _check_next_flags(size_t node, type_bits f)
- {
- auto n = _p(node);
- type_bits o = n->m_type; // old
- C4_UNUSED(o);
- if(f & MAP)
- {
- RYML_ASSERT_MSG((f & SEQ) == 0, "cannot mark simultaneously as map and seq");
- RYML_ASSERT_MSG((f & VAL) == 0, "cannot mark simultaneously as map and val");
- RYML_ASSERT_MSG((o & SEQ) == 0, "cannot turn a seq into a map; clear first");
- RYML_ASSERT_MSG((o & VAL) == 0, "cannot turn a val into a map; clear first");
- }
- else if(f & SEQ)
- {
- RYML_ASSERT_MSG((f & MAP) == 0, "cannot mark simultaneously as seq and map");
- RYML_ASSERT_MSG((f & VAL) == 0, "cannot mark simultaneously as seq and val");
- RYML_ASSERT_MSG((o & MAP) == 0, "cannot turn a map into a seq; clear first");
- RYML_ASSERT_MSG((o & VAL) == 0, "cannot turn a val into a seq; clear first");
- }
- if(f & KEY)
- {
- RYML_ASSERT(!is_root(node));
- auto pid = parent(node); C4_UNUSED(pid);
- RYML_ASSERT(is_map(pid));
- }
- if((f & VAL) && !is_root(node))
- {
- auto pid = parent(node); C4_UNUSED(pid);
- RYML_ASSERT(is_map(pid) || is_seq(pid));
- }
- }
- #endif
-
- inline void _set_flags(size_t node, NodeType_e f) { _check_next_flags(node, f); _p(node)->m_type = f; }
- inline void _set_flags(size_t node, type_bits f) { _check_next_flags(node, f); _p(node)->m_type = f; }
-
- inline void _add_flags(size_t node, NodeType_e f) { NodeData *d = _p(node); type_bits fb = f | d->m_type; _check_next_flags(node, fb); d->m_type = (NodeType_e) fb; }
- inline void _add_flags(size_t node, type_bits f) { NodeData *d = _p(node); f |= d->m_type; _check_next_flags(node, f); d->m_type = f; }
-
- inline void _rem_flags(size_t node, NodeType_e f) { NodeData *d = _p(node); type_bits fb = d->m_type & ~f; _check_next_flags(node, fb); d->m_type = (NodeType_e) fb; }
- inline void _rem_flags(size_t node, type_bits f) { NodeData *d = _p(node); f = d->m_type & ~f; _check_next_flags(node, f); d->m_type = f; }
-
- void _set_key(size_t node, csubstr key, type_bits more_flags=0)
- {
- _p(node)->m_key.scalar = key;
- _add_flags(node, KEY|more_flags);
- }
- void _set_key(size_t node, NodeScalar const& key, type_bits more_flags=0)
- {
- _p(node)->m_key = key;
- _add_flags(node, KEY|more_flags);
- }
-
- void _set_val(size_t node, csubstr val, type_bits more_flags=0)
- {
- RYML_ASSERT(num_children(node) == 0);
- RYML_ASSERT(!is_seq(node) && !is_map(node));
- _p(node)->m_val.scalar = val;
- _add_flags(node, VAL|more_flags);
- }
- void _set_val(size_t node, NodeScalar const& val, type_bits more_flags=0)
- {
- RYML_ASSERT(num_children(node) == 0);
- RYML_ASSERT( ! is_container(node));
- _p(node)->m_val = val;
- _add_flags(node, VAL|more_flags);
- }
-
- void _set(size_t node, NodeInit const& i)
- {
- RYML_ASSERT(i._check());
- NodeData *n = _p(node);
- RYML_ASSERT(n->m_key.scalar.empty() || i.key.scalar.empty() || i.key.scalar == n->m_key.scalar);
- _add_flags(node, i.type);
- if(n->m_key.scalar.empty())
- {
- if( ! i.key.scalar.empty())
- {
- _set_key(node, i.key.scalar);
- }
- }
- n->m_key.tag = i.key.tag;
- n->m_val = i.val;
- }
-
- void _set_parent_as_container_if_needed(size_t in)
- {
- NodeData const* n = _p(in);
- size_t ip = parent(in);
- if(ip != NONE)
- {
- if( ! (is_seq(ip) || is_map(ip)))
- {
- if((in == first_child(ip)) && (in == last_child(ip)))
- {
- if( ! n->m_key.empty() || has_key(in))
- {
- _add_flags(ip, MAP);
- }
- else
- {
- _add_flags(ip, SEQ);
- }
- }
- }
- }
- }
-
- void _seq2map(size_t node)
- {
- RYML_ASSERT(is_seq(node));
- for(size_t i = first_child(node); i != NONE; i = next_sibling(i))
- {
- NodeData *C4_RESTRICT ch = _p(i);
- if(ch->m_type.is_keyval())
- continue;
- ch->m_type.add(KEY);
- ch->m_key = ch->m_val;
- }
- auto *C4_RESTRICT n = _p(node);
- n->m_type.rem(SEQ);
- n->m_type.add(MAP);
- }
-
- size_t _do_reorder(size_t *node, size_t count);
-
- void _swap(size_t n_, size_t m_);
- void _swap_props(size_t n_, size_t m_);
- void _swap_hierarchy(size_t n_, size_t m_);
- void _copy_hierarchy(size_t dst_, size_t src_);
-
- inline void _copy_props(size_t dst_, size_t src_)
- {
- _copy_props(dst_, this, src_);
- }
-
- inline void _copy_props_wo_key(size_t dst_, size_t src_)
- {
- _copy_props_wo_key(dst_, this, src_);
- }
-
- void _copy_props(size_t dst_, Tree const* that_tree, size_t src_)
- {
- auto & C4_RESTRICT dst = *_p(dst_);
- auto const& C4_RESTRICT src = *that_tree->_p(src_);
- dst.m_type = src.m_type;
- dst.m_key = src.m_key;
- dst.m_val = src.m_val;
- }
-
- void _copy_props_wo_key(size_t dst_, Tree const* that_tree, size_t src_)
- {
- auto & C4_RESTRICT dst = *_p(dst_);
- auto const& C4_RESTRICT src = *that_tree->_p(src_);
- dst.m_type = (src.m_type & ~_KEYMASK) | (dst.m_type & _KEYMASK);
- dst.m_val = src.m_val;
- }
-
- inline void _clear_type(size_t node)
- {
- _p(node)->m_type = NOTYPE;
- }
-
- inline void _clear(size_t node)
- {
- auto *C4_RESTRICT n = _p(node);
- n->m_type = NOTYPE;
- n->m_key.clear();
- n->m_val.clear();
- n->m_parent = NONE;
- n->m_first_child = NONE;
- n->m_last_child = NONE;
- }
-
- inline void _clear_key(size_t node)
- {
- _p(node)->m_key.clear();
- _rem_flags(node, KEY);
- }
-
- inline void _clear_val(size_t node)
- {
- _p(node)->m_val.clear();
- _rem_flags(node, VAL);
- }
-
-private:
-
- void _clear_range(size_t first, size_t num);
-
- size_t _claim();
- void _claim_root();
- void _release(size_t node);
- void _free_list_add(size_t node);
- void _free_list_rem(size_t node);
-
- void _set_hierarchy(size_t node, size_t parent, size_t after_sibling);
- void _rem_hierarchy(size_t node);
-
-public:
-
- // members are exposed, but you should NOT access them directly
-
- NodeData * m_buf;
- size_t m_cap;
-
- size_t m_size;
-
- size_t m_free_head;
- size_t m_free_tail;
-
- substr m_arena;
- size_t m_arena_pos;
-
- Callbacks m_callbacks;
-
- TagDirective m_tag_directives[RYML_MAX_TAG_DIRECTIVES];
-
-};
-
-} // namespace yml
-} // namespace c4
-
-
-C4_SUPPRESS_WARNING_MSVC_POP
-C4_SUPPRESS_WARNING_GCC_CLANG_POP
-
-
-#endif /* _C4_YML_TREE_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/writer.hpp b/thirdparty/ryml/src/c4/yml/writer.hpp
deleted file mode 100644
index 29e32d47b..000000000
--- a/thirdparty/ryml/src/c4/yml/writer.hpp
+++ /dev/null
@@ -1,229 +0,0 @@
-#ifndef _C4_YML_WRITER_HPP_
-#define _C4_YML_WRITER_HPP_
-
-#ifndef _C4_YML_COMMON_HPP_
-#include "./common.hpp"
-#endif
-
-#include <c4/substr.hpp>
-#include <stdio.h> // fwrite(), fputc()
-#include <string.h> // memcpy()
-
-
-namespace c4 {
-namespace yml {
-
-
-/** Repeat-Character: a character to be written a number of times. */
-struct RepC
-{
- char c;
- size_t num_times;
-};
-inline RepC indent_to(size_t num_levels)
-{
- return {' ', size_t(2) * num_levels};
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-/** A writer that outputs to a file. Defaults to stdout. */
-struct WriterFile
-{
- FILE * m_file;
- size_t m_pos;
-
- WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {}
-
- inline substr _get(bool /*error_on_excess*/)
- {
- substr sp;
- sp.str = nullptr;
- sp.len = m_pos;
- return sp;
- }
-
- template<size_t N>
- inline void _do_write(const char (&a)[N])
- {
- fwrite(a, sizeof(char), N - 1, m_file);
- m_pos += N - 1;
- }
-
- inline void _do_write(csubstr sp)
- {
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma GCC diagnostic ignored "-Wsign-conversion"
- #elif defined(__GNUC__)
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wsign-conversion"
- #endif
- if(sp.empty()) return;
- fwrite(sp.str, sizeof(csubstr::char_type), sp.len, m_file);
- m_pos += sp.len;
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #elif defined(__GNUC__)
- # pragma GCC diagnostic pop
- #endif
- }
-
- inline void _do_write(const char c)
- {
- fputc(c, m_file);
- ++m_pos;
- }
-
- inline void _do_write(RepC const rc)
- {
- for(size_t i = 0; i < rc.num_times; ++i)
- {
- fputc(rc.c, m_file);
- }
- m_pos += rc.num_times;
- }
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-/** A writer that outputs to an STL-like ostream. */
-template<class OStream>
-struct WriterOStream
-{
- OStream& m_stream;
- size_t m_pos;
-
- WriterOStream(OStream &s) : m_stream(s), m_pos(0) {}
-
- inline substr _get(bool /*error_on_excess*/)
- {
- substr sp;
- sp.str = nullptr;
- sp.len = m_pos;
- return sp;
- }
-
- template<size_t N>
- inline void _do_write(const char (&a)[N])
- {
- m_stream.write(a, N - 1);
- m_pos += N - 1;
- }
-
- inline void _do_write(csubstr sp)
- {
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma GCC diagnostic ignored "-Wsign-conversion"
- #elif defined(__GNUC__)
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wsign-conversion"
- #endif
- if(sp.empty()) return;
- m_stream.write(sp.str, sp.len);
- m_pos += sp.len;
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #elif defined(__GNUC__)
- # pragma GCC diagnostic pop
- #endif
- }
-
- inline void _do_write(const char c)
- {
- m_stream.put(c);
- ++m_pos;
- }
-
- inline void _do_write(RepC const rc)
- {
- for(size_t i = 0; i < rc.num_times; ++i)
- {
- m_stream.put(rc.c);
- }
- m_pos += rc.num_times;
- }
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-/** a writer to a substr */
-struct WriterBuf
-{
- substr m_buf;
- size_t m_pos;
-
- WriterBuf(substr sp) : m_buf(sp), m_pos(0) {}
-
- inline substr _get(bool error_on_excess)
- {
- if(m_pos <= m_buf.len)
- {
- return m_buf.first(m_pos);
- }
- if(error_on_excess)
- {
- c4::yml::error("not enough space in the given buffer");
- }
- substr sp;
- sp.str = nullptr;
- sp.len = m_pos;
- return sp;
- }
-
- template<size_t N>
- inline void _do_write(const char (&a)[N])
- {
- RYML_ASSERT( ! m_buf.overlaps(a));
- if(m_pos + N-1 <= m_buf.len)
- {
- memcpy(&(m_buf[m_pos]), a, N-1);
- }
- m_pos += N-1;
- }
-
- inline void _do_write(csubstr sp)
- {
- if(sp.empty()) return;
- RYML_ASSERT( ! sp.overlaps(m_buf));
- if(m_pos + sp.len <= m_buf.len)
- {
- memcpy(&(m_buf[m_pos]), sp.str, sp.len);
- }
- m_pos += sp.len;
- }
-
- inline void _do_write(const char c)
- {
- if(m_pos + 1 <= m_buf.len)
- {
- m_buf[m_pos] = c;
- }
- ++m_pos;
- }
-
- inline void _do_write(RepC const rc)
- {
- if(m_pos + rc.num_times <= m_buf.len)
- {
- for(size_t i = 0; i < rc.num_times; ++i)
- {
- m_buf[m_pos + i] = rc.c;
- }
- }
- m_pos += rc.num_times;
- }
-};
-
-
-} // namespace yml
-} // namespace c4
-
-#endif /* _C4_YML_WRITER_HPP_ */
diff --git a/thirdparty/ryml/src/c4/yml/yml.hpp b/thirdparty/ryml/src/c4/yml/yml.hpp
deleted file mode 100644
index 36f78fe82..000000000
--- a/thirdparty/ryml/src/c4/yml/yml.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _C4_YML_YML_HPP_
-#define _C4_YML_YML_HPP_
-
-#include "c4/yml/tree.hpp"
-#include "c4/yml/node.hpp"
-#include "c4/yml/emit.hpp"
-#include "c4/yml/parse.hpp"
-#include "c4/yml/preprocess.hpp"
-
-#endif // _C4_YML_YML_HPP_
diff --git a/thirdparty/ryml/src/ryml-gdbtypes.py b/thirdparty/ryml/src/ryml-gdbtypes.py
deleted file mode 100644
index 2625a6ccd..000000000
--- a/thirdparty/ryml/src/ryml-gdbtypes.py
+++ /dev/null
@@ -1,391 +0,0 @@
-# To make this file known to Qt Creator using:
-# Tools > Options > Debugger > Locals & Expressions > Extra Debugging Helpers
-# Any contents here will be picked up by GDB, LLDB, and CDB based
-# debugging in Qt Creator automatically.
-
-
-# Example to display a simple type
-# template<typename U, typename V> struct MapNode
-# {
-# U key;
-# V data;
-# }
-#
-# def qdump__MapNode(d, value):
-# d.putValue("This is the value column contents")
-# d.putExpandable()
-# if d.isExpanded():
-# with Children(d):
-# # Compact simple case.
-# d.putSubItem("key", value["key"])
-# # Same effect, with more customization possibilities.
-# with SubItem(d, "data")
-# d.putItem("data", value["data"])
-
-# Check http://doc.qt.io/qtcreator/creator-debugging-helpers.html
-# for more details or look at qttypes.py, stdtypes.py, boosttypes.py
-# for more complex examples.
-
-# to try parsing:
-# env PYTHONPATH=/usr/share/qtcreator/debugger/ python src/ryml-gdbtypes.py
-
-
-import dumper
-#from dumper import Dumper, Value, Children, SubItem
-#from dumper import SubItem, Children
-from dumper import *
-
-import sys
-import os
-
-
-# -----------------------------------------------------------------------------
-# -----------------------------------------------------------------------------
-# -----------------------------------------------------------------------------
-
-# QtCreator makes it really hard to figure out problems in this code.
-# So here are some debugging utilities.
-
-
-# FIXME. this decorator is not working; find out why.
-def dbglog(func):
- """a decorator that logs entry and exit of functions"""
- if not _DBG:
- return func
- def func_wrapper(*args, **kwargs):
- _dbg_enter(func.__name__)
- ret = func(*args, **kwargs)
- _dbg_exit(func.__name__)
- return ret
- return func_wrapper
-
-
-_DBG = False
-_dbg_log = None
-_dbg_stack = 0
-def _dbg(*args, **kwargs):
- global _dbg_log, _dbg_stack
- if not _DBG:
- return
- if _dbg_log is None:
- filename = os.path.join(os.path.dirname(__file__), "dbg.txt")
- _dbg_log = open(filename, "w")
- kwargs['file'] = _dbg_log
- kwargs['flush'] = True
- print(" " * _dbg_stack, *args, **kwargs)
-
-
-def _dbg_enter(name):
- global _dbg_stack
- _dbg(name, "- enter")
- _dbg_stack += 1
-
-
-def _dbg_exit(name):
- global _dbg_stack
- _dbg_stack -= 1
- _dbg(name, "- exit!")
-
-
-
-# -----------------------------------------------------------------------------
-# -----------------------------------------------------------------------------
-# -----------------------------------------------------------------------------
-
-
-NPOS = 18446744073709551615
-MAX_SUBSTR_LEN_DISPLAY = 80
-MAX_SUBSTR_LEN_EXPAND = 1000
-
-
-def get_str_value(d, value, limit=0):
- # adapted from dumper.py::Dumper::putCharArrayValue()
- m_str = value["str"].pointer()
- m_len = value["len"].integer()
- if m_len == NPOS:
- _dbg("getstr... 1", m_len)
- m_str = "!!!!!<npos>!!!!!"
- m_len = len(m_str)
- return m_str, m_len
- if limit == 0:
- limit = d.displayStringLimit
- elided, shown = d.computeLimit(m_len, limit)
- mem = bytes(d.readRawMemory(m_str, shown))
- mem = mem.decode('utf8')
- return mem, m_len
-
-
-def __display_csubstr(d, value, limit=0):
- m_str, m_len = get_str_value(d, value)
- safe_len = min(m_len, MAX_SUBSTR_LEN_DISPLAY)
- disp = m_str[0:safe_len]
- # ensure the string escapes characters like \n\r\t etc
- disp = disp.encode('unicode_escape').decode('utf8')
- # WATCHOUT. quotes in the string will make qtcreator hang!!!
- disp = disp.replace('"', '\\"')
- disp = disp.replace('\'', '\\')
- if m_len <= MAX_SUBSTR_LEN_DISPLAY:
- d.putValue(f"[{m_len}] '{disp}'")
- else:
- d.putValue(f"[{m_len}] '{disp}'...")
- return m_str, m_len
-
-
-def qdump__c4__csubstr(d, value):
- m_str, m_len = __display_csubstr(d, value)
- d.putExpandable()
- if d.isExpanded():
- with Children(d):
- safe_len = min(m_len, MAX_SUBSTR_LEN_EXPAND)
- for i in range(safe_len):
- ct = d.createType('char')
- d.putSubItem(safe_len, d.createValue(value["str"].pointer() + i, ct))
- d.putSubItem("len", value["len"])
- d.putPtrItem("str", value["str"].pointer())
-
-
-def qdump__c4__substr(d, value):
- qdump__c4__csubstr(d, value)
-
-
-def qdump__c4__basic_substring(d, value):
- qdump__c4__csubstr(d, value)
-
-
-def qdump__c4__yml__NodeScalar(d, value):
- alen = value["anchor"]["len"].integer()
- tlen = value["tag" ]["len"].integer()
- m_str, m_len = get_str_value(d, value["scalar"])
- if alen == 0 and tlen == 0:
- d.putValue(f'\'{m_str}\'')
- elif alen == 0 and tlen > 0:
- d.putValue(f'\'{m_str}\' [Ta]')
- elif alen > 0 and tlen == 0:
- d.putValue(f'\'{m_str}\' [tA]')
- elif alen > 0 and tlen > 0:
- d.putValue(f'\'{m_str}\' [TA]')
- d.putExpandable()
- if d.isExpanded():
- with Children(d):
- d.putSubItem("[scalar]", value["scalar"])
- if tlen > 0:
- d.putSubItem("[tag]", value["tag"])
- if alen > 0:
- d.putSubItem("[anchor or ref]", value["anchor"])
-
-
-def _format_enum_value(int_value, enum_map):
- str_value = enum_map.get(int_value, None)
- display = f'{int_value}' if str_value is None else f'{str_value} ({int_value})'
- return display
-
-
-def _format_bitmask_value(int_value, enum_map):
- str_value = enum_map.get(int_value, None)
- if str_value:
- return f'{str_value} ({int_value})'
- else:
- out = ""
- orig = int_value
- # do in reverse to get compound flags first
- for k, v in reversed(enum_map.items()):
- if (k != 0):
- if (int_value & k) == k:
- if len(out) > 0:
- out += '|'
- out += v
- int_value &= ~k
- else:
- if len(out) == 0 and int_value == 0:
- return v
- if out == "":
- return f'{int_value}'
- return f"{out} ({orig})"
-
-
-def _c4bit(*ints):
- ret = 0
- for i in ints:
- ret |= 1 << i
- return ret
-
-
-node_types = {
- 0: "NOTYPE",
- _c4bit(0): "VAL" ,
- _c4bit(1): "KEY" ,
- _c4bit(2): "MAP" ,
- _c4bit(3): "SEQ" ,
- _c4bit(4): "DOC" ,
- _c4bit(5,3): "STREAM",
- _c4bit(6): "KEYREF" ,
- _c4bit(7): "VALREF" ,
- _c4bit(8): "KEYANCH" ,
- _c4bit(9): "VALANCH" ,
- _c4bit(10): "KEYTAG" ,
- _c4bit(11): "VALTAG" ,
- _c4bit(12): "VALQUO" ,
- _c4bit(13): "KEYQUO" ,
- _c4bit(1,0): "KEYVAL",
- _c4bit(1,3): "KEYSEQ",
- _c4bit(1,2): "KEYMAP",
- _c4bit(4,2): "DOCMAP",
- _c4bit(4,3): "DOCSEQ",
- _c4bit(4,0): "DOCVAL",
- #
- _c4bit(14): "STYLE_FLOW_SL",
- _c4bit(15): "STYLE_FLOW_ML",
- _c4bit(16): "STYLE_BLOCK",
- #
- _c4bit(17): "KEY_LITERAL",
- _c4bit(18): "VAL_LITERAL",
- _c4bit(19): "KEY_FOLDED",
- _c4bit(20): "VAL_FOLDED",
- _c4bit(21): "KEY_SQUO",
- _c4bit(22): "VAL_SQUO",
- _c4bit(23): "KEY_DQUO",
- _c4bit(24): "VAL_DQUO",
- _c4bit(25): "KEY_PLAIN",
- _c4bit(26): "VAL_PLAIN",
-}
-node_types_rev = {v: k for k, v in node_types.items()}
-
-
-def _node_type_has_all(node_type_value, type_name):
- exp = node_types_rev[type_name]
- return (node_type_value & exp) == exp
-
-
-def _node_type_has_any(node_type_value, type_name):
- exp = node_types_rev[type_name]
- return (node_type_value & exp) != 0
-
-
-def qdump__c4__yml__NodeType_e(d, value):
- v = _format_bitmask_value(value.integer(), node_types)
- d.putValue(v)
-
-
-def qdump__c4__yml__NodeType(d, value):
- qdump__c4__yml__NodeType_e(d, value["type"])
-
-
-def qdump__c4__yml__NodeData(d, value):
- d.putValue("wtf")
- ty = _format_bitmask_value(value.integer(), node_types)
- t = value["m_type"]["type"].integer()
- k = value["m_key"]["scalar"]
- v = value["m_val"]["scalar"]
- sk, lk = get_str_value(d, k)
- sv, lv = get_str_value(d, v)
- if _node_type_has_all(t, "KEYVAL"):
- d.putValue(f"'{sk}': '{sv}' {ty}")
- elif _node_type_has_any(t, "KEY"):
- d.putValue(f"'{sk}': {ty}")
- elif _node_type_has_any(t, "VAL"):
- d.putValue(f"'{sv}' {ty}")
- else:
- d.putValue(f"{ty}")
- d.putExpandable()
- if d.isExpanded():
- with Children(d):
- d.putSubItem("m_type", value["m_type"])
- # key
- if _node_type_has_any(t, "KEY"):
- d.putSubItem("m_key", value["m_key"])
- if _node_type_has_any(t, "KEYREF"):
- with SubItem(d, "m_key.ref"):
- s_, _ = get_str_value(d, value["m_key"]["anchor"])
- d.putValue(f"'{s_}'")
- if _node_type_has_any(t, "KEYANCH"):
- with SubItem(d, "m_key.anchor"):
- s_, _ = get_str_value(d, value["m_key"]["anchor"])
- d.putValue(f"'{s_}'")
- if _node_type_has_any(t, "KEYTAG"):
- with SubItem(d, "m_key.tag"):
- s_, _ = get_str_value(d, value["m_key"]["tag"])
- d.putValue(f"'{s_}'")
- # val
- if _node_type_has_any(t, "VAL"):
- d.putSubItem("m_val", value["m_val"])
- if _node_type_has_any(t, "VALREF"):
- with SubItem(d, "m_val.ref"):
- s_, _ = get_str_value(d, value["m_val"]["anchor"])
- d.putValue(f"'{s_}'")
- if _node_type_has_any(t, "VALANCH"):
- with SubItem(d, "m_val.anchor"):
- s_, _ = get_str_value(d, value["m_val"]["anchor"])
- d.putValue(f"'{s_}'")
- if _node_type_has_any(t, "VALTAG"):
- with SubItem(d, "m_val.tag"):
- s_, _ = get_str_value(d, value["m_val"]["tag"])
- d.putValue(f"'{s_}'")
- # hierarchy
- _dump_node_index(d, "m_parent", value)
- _dump_node_index(d, "m_first_child", value)
- _dump_node_index(d, "m_last_child", value)
- _dump_node_index(d, "m_next_sibling", value)
- _dump_node_index(d, "m_prev_sibling", value)
-
-
-def _dump_node_index(d, name, value):
- if int(value[name].integer()) == NPOS:
- pass
- #with SubItem(d, name):
- # d.putValue("-")
- else:
- d.putSubItem(name, value[name])
-
-
-# c4::yml::Tree
-def qdump__c4__yml__Tree(d, value):
- m_size = value["m_size"].integer()
- m_cap = value["m_cap"].integer()
- d.putExpandable()
- if d.isExpanded():
- #d.putArrayData(value["m_buf"], m_size, value["m_buf"].dereference())
- with Children(d):
- with SubItem(d, f"[nodes]"):
- d.putItemCount(m_size)
- d.putArrayData(value["m_buf"].pointer(), m_size, value["m_buf"].type.dereference())
- d.putPtrItem("m_buf", value["m_buf"].pointer())
- d.putIntItem("m_size", value["m_size"])
- d.putIntItem("m_cap (capacity)", value["m_cap"])
- d.putIntItem("[slack]", m_cap - m_size)
- d.putIntItem("m_free_head", value["m_free_head"])
- d.putIntItem("m_free_tail", value["m_free_tail"])
- d.putSubItem("m_arena", value["m_arena"])
-
-
-def qdump__c4__yml__detail__stack(d, value):
- T = value.type[0]
- N = value.type[0]
- m_size = value["m_size"].integer()
- m_capacity = value["m_capacity"].integer()
- d.putItemCount(m_size)
- if d.isExpanded():
- with Children(d):
- with SubItem(d, f"[nodes]"):
- d.putItemCount(m_size)
- d.putArrayData(value["m_stack"].pointer(), m_size, T)
- d.putIntItem("m_size", value["m_size"])
- d.putIntItem("m_capacity", value["m_capacity"])
- #d.putIntItem("[small capacity]", N)
- d.putIntItem("[is large]", value["m_buf"].address() == value["m_stack"].pointer())
- d.putPtrItem("m_stack", value["m_stack"].pointer())
- d.putPtrItem("m_buf", value["m_buf"].address())
-
-
-def qdump__c4__yml__detail__ReferenceResolver__refdata(d, value):
- node = value["node"].integer()
- ty = _format_bitmask_value(value["type"].integer(), node_types)
- d.putValue(f'{node} {ty}')
- d.putExpandable()
- if d.isExpanded():
- with Children(d):
- d.putSubItem("type", value["type"])
- d.putSubItem("node", value["node"])
- _dump_node_index(d, "prev_anchor", value)
- _dump_node_index(d, "target", value)
- _dump_node_index(d, "parent_ref", value)
- _dump_node_index(d, "parent_ref_sibling", value)
diff --git a/thirdparty/ryml/src/ryml.hpp b/thirdparty/ryml/src/ryml.hpp
deleted file mode 100644
index c2b3e74b2..000000000
--- a/thirdparty/ryml/src/ryml.hpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _RYML_HPP_
-#define _RYML_HPP_
-
-#include "c4/yml/yml.hpp"
-
-namespace ryml {
-using namespace c4::yml;
-using namespace c4;
-}
-
-#endif /* _RYML_HPP_ */
diff --git a/thirdparty/ryml/src/ryml.natvis b/thirdparty/ryml/src/ryml.natvis
deleted file mode 100644
index 5e43b1a5c..000000000
--- a/thirdparty/ryml/src/ryml.natvis
+++ /dev/null
@@ -1,194 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-Very good intro:
-@see https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2017
-@see https://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2
-See also:
-@see http://blogs.msdn.com/b/vcblog/archive/2013/06/28/using-visual-studio-2013-to-write-maintainable-native-visualizations-natvis.aspx?PageIndex=2
-@see http://blogs.msdn.com/b/vcblog/archive/2015/09/28/debug-visualizers-in-visual-c-2015.aspx
-@see http://stackoverflow.com/questions/36883414/limit-display-of-char-in-natvis-file-to-specific-length
--->
-
-<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
-
- <Type Name="c4::yml::NodeScalar">
- <DisplayString Condition="(tag.len == 0) &amp;&amp; (anchor.len == 0)">{scalar.str,[scalar.len]}</DisplayString>
- <DisplayString Condition="(tag.len > 0) &amp;&amp; (anchor.len == 0)">{scalar.str,[scalar.len]} [T]</DisplayString>
- <DisplayString Condition="(tag.len == 0) &amp;&amp; (anchor.len > 0)">{scalar.str,[scalar.len]} [A]</DisplayString>
- <DisplayString Condition="(tag.len > 0) &amp;&amp; (anchor.len > 0)">{scalar.str,[scalar.len]} [T][A]</DisplayString>
- <Expand>
- <Item Name="scalar">scalar</Item>
- <Item Name="tag">tag</Item>
- <Item Name="anchor">anchor</Item>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::NodeType">
- <DisplayString>{type}</DisplayString>
- <Expand>
- <Synthetic Name="[enabled bits]">
- <Expand>
- <Item Name="[0]" Condition="(type &amp; c4::yml::VAL) != 0">c4::yml::VAL</Item>
- <Item Name="[1]" Condition="(type &amp; c4::yml::KEY) != 0">c4::yml::KEY</Item>
- <Item Name="[2]" Condition="(type &amp; c4::yml::MAP) != 0">c4::yml::MAP</Item>
- <Item Name="[3]" Condition="(type &amp; c4::yml::SEQ) != 0">c4::yml::SEQ</Item>
- <Item Name="[4]" Condition="(type &amp; c4::yml::DOC) != 0">c4::yml::DOC</Item>
- <Item Name="[5]" Condition="(type &amp; c4::yml::STREAM) != 0">c4::yml::STREAM</Item>
- <Item Name="[6]" Condition="(type &amp; c4::yml::KEYREF) != 0">c4::yml::KEYREF</Item>
- <Item Name="[7]" Condition="(type &amp; c4::yml::VALREF) != 0">c4::yml::VALREF</Item>
- <Item Name="[8]" Condition="(type &amp; c4::yml::KEYANCH) != 0">c4::yml::KEYANCH</Item>
- <Item Name="[9]" Condition="(type &amp; c4::yml::VALANCH) != 0">c4::yml::VALANCH</Item>
- <Item Name="[10]" Condition="(type &amp; c4::yml::KEYTAG) != 0">c4::yml::KEYTAG</Item>
- <Item Name="[11]" Condition="(type &amp; c4::yml::VALTAG) != 0">c4::yml::VALTAG</Item>
- <Item Name="[12]" Condition="(type &amp; c4::yml::VALQUO) != 0">c4::yml::VALQUO</Item>
- <Item Name="[13]" Condition="(type &amp; c4::yml::KEYQUO) != 0">c4::yml::KEYQUO</Item>
- </Expand>
- </Synthetic>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::NodeData">
- <DisplayString Condition="((m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((m_type.type &amp; c4::yml::VAL) == c4::yml::VAL)">[KEYVAL] {m_key.scalar.str,[m_key.scalar.len]}: {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
- <DisplayString Condition="((m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((m_type.type &amp; c4::yml::SEQ) == c4::yml::SEQ)">[KEYSEQ] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
- <DisplayString Condition="((m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((m_type.type &amp; c4::yml::MAP) == c4::yml::MAP)">[KEYMAP] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
- <DisplayString Condition="((m_type.type &amp; c4::yml::DOC ) == c4::yml::DOC) &amp;&amp; ((m_type.type &amp; c4::yml::SEQ) == c4::yml::SEQ)">[DOCSEQ]</DisplayString>
- <DisplayString Condition="((m_type.type &amp; c4::yml::DOC ) == c4::yml::DOC) &amp;&amp; ((m_type.type &amp; c4::yml::MAP) == c4::yml::MAP)">[DOCMAP]</DisplayString>
- <DisplayString Condition="(m_type.type &amp; c4::yml::VAL ) == c4::yml::VAL" >[VAL] {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
- <DisplayString Condition="(m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY" >[KEY] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
- <DisplayString Condition="(m_type.type &amp; c4::yml::SEQ ) == c4::yml::SEQ" >[SEQ]</DisplayString>
- <DisplayString Condition="(m_type.type &amp; c4::yml::MAP ) == c4::yml::MAP" >[MAP]</DisplayString>
- <DisplayString Condition="(m_type.type &amp; c4::yml::DOC ) == c4::yml::DOC" >[DOC]</DisplayString>
- <DisplayString Condition="(m_type.type &amp; c4::yml::STREAM) == c4::yml::STREAM">[STREAM]</DisplayString>
- <DisplayString Condition="(m_type.type &amp; c4::yml::NOTYPE) == c4::yml::NOTYPE">[NOTYPE]</DisplayString>
- <Expand>
- <Item Name="type">m_type</Item>
- <Item Name="key" Condition="(m_type.type &amp; c4::yml::KEY) != 0">m_key</Item>
- <Item Name="val" Condition="(m_type.type &amp; c4::yml::VAL) != 0">m_val</Item>
- <Item Name="key quoted" Condition="((m_type.type &amp; c4::yml::KEY) != 0) &amp;&amp; ((m_type.type &amp; c4::yml::KEYQUO) != 0)">c4::yml::KEYQUO</Item>
- <Item Name="val quoted" Condition="((m_type.type &amp; c4::yml::VAL) != 0) &amp;&amp; ((m_type.type &amp; c4::yml::VALQUO) != 0)">c4::yml::VALQUO</Item>
- <Item Name="key ref" Condition="(m_type.type &amp; c4::yml::KEYREF) != 0">m_key.anchor</Item>
- <Item Name="val ref" Condition="(m_type.type &amp; c4::yml::VALREF) != 0">m_val.anchor</Item>
- <Item Name="key anchor" Condition="(m_type.type &amp; c4::yml::KEYANCH) != 0">m_key.anchor</Item>
- <Item Name="val anchor" Condition="(m_type.type &amp; c4::yml::VALANCH) != 0">m_val.anchor</Item>
- <Item Name="parent">m_parent</Item>
- <Item Name="first child" Condition="m_first_child != c4::yml::NONE">m_first_child</Item>
- <Item Name="last child" Condition="m_last_child != c4::yml::NONE">m_last_child</Item>
- <Item Name="prev sibling" Condition="m_prev_sibling != c4::yml::NONE">m_prev_sibling</Item>
- <Item Name="next sibling" Condition="m_next_sibling != c4::yml::NONE">m_next_sibling</Item>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::Tree">
- <DisplayString>sz={m_size}, cap={m_cap}</DisplayString>
- <Expand>
- <Item Name="[size]">m_size</Item>
- <Item Name="[capacity]">m_cap</Item>
- <Synthetic Name="[buffer]">
- <Expand>
- <ArrayItems>
- <Size>m_cap</Size>
- <ValuePointer>m_buf</ValuePointer>
- </ArrayItems>
- </Expand>
- </Synthetic>
- <Item Name="free head">m_free_head</Item>
- <Item Name="arena">m_arena</Item>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::Tree::_lookup_path_token">
- <DisplayString>{value} ({type})</DisplayString>
- <Expand>
- <Item Name="value">value</Item>
- <Item Name="type">type</Item>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::Tree::lookup_result">
- <DisplayString>{path} -- target={target} closest={closest}</DisplayString>
- <Expand>
- <Item Name="target">target</Item>
- <Item Name="closest">closest</Item>
- <Item Name="path_pos">path_pos</Item>
- <Item Name="path">path</Item>
- <Synthetic Name="[resolved]">
- <DisplayString>{path.str,[path_pos]}</DisplayString>
- </Synthetic>
- <Synthetic Name="[unresolved]">
- <DisplayString>{path.str+path_pos,[path.len-path_pos]}</DisplayString>
- </Synthetic>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::NodeRef">
- <DisplayString Condition="(m_id == c4::yml::NONE)">(void)</DisplayString>
- <DisplayString Condition="(m_seed.len != c4::yml::NONE) &amp;&amp; (m_seed.str == nullptr)">[INDEX SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
- <DisplayString Condition="(m_seed.len != c4::yml::NONE) &amp;&amp; (m_seed.str != nullptr)">[NAMED SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
- <DisplayString>{*(m_tree->m_buf + m_id)}</DisplayString>
- <Expand>
- <Item Name="id">m_id</Item>
- <Item Name="elm">*(m_tree->m_buf + m_id)</Item>
- <Item Name="tree">m_tree</Item>
- <Synthetic Name="[children]" Condition="(m_id != c4::yml::NONE) &amp;&amp; ((m_tree->m_buf + m_id)->m_type.type &amp; (c4::yml::MAP|c4::yml::SEQ) != 0)">
- <Expand>
- <CustomListItems>
- <Variable Name="tree" InitialValue="m_tree"/>
- <Variable Name="buf" InitialValue="m_tree->m_buf"/>
- <Variable Name="curr" InitialValue="(m_tree->m_buf + m_id)->m_first_child"/>
- <Loop>
- <Item>buf + curr</Item>
- <Exec>curr = (buf + curr)->m_next_sibling</Exec>
- <Break Condition="curr == c4::yml::NONE"/>
- </Loop>
- </CustomListItems>
- </Expand>
- </Synthetic>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::detail::ReferenceResolver">
- <DisplayString>#refs={refs.m_size} #nodes={t->m_size}</DisplayString>
- <Expand>
- <Synthetic Name="[ref_nodes]">
- <Expand>
- <CustomListItems>
- <Variable Name="curr" InitialValue="0"/>
- <Loop>
- <Item>t->m_buf + (refs.m_stack + curr)->node</Item>
- <Exec>curr = curr+1</Exec>
- <Break Condition="curr >= refs.m_size"/>
- </Loop>
- </CustomListItems>
- </Expand>
- </Synthetic>
- <Synthetic Name="[refs]">
- <Expand>
- <ArrayItems>
- <Size>refs.m_size</Size>
- <ValuePointer>refs.m_stack</ValuePointer>
- </ArrayItems>
- </Expand>
- </Synthetic>
- <Item Name="[tree]">t</Item>
- </Expand>
- </Type>
-
- <Type Name="c4::yml::detail::stack&lt;*,*&gt;">
- <DisplayString>sz={m_size} cap={m_capacity}</DisplayString>
- <Expand>
- <Item Name="[size]">m_size</Item>
- <Item Name="[capacity]">m_capacity</Item>
- <Item Name="[is small]">m_buf == m_stack</Item>
- <Synthetic Name="[items]">
- <Expand>
- <ArrayItems>
- <Size>m_size</Size>
- <ValuePointer>m_stack</ValuePointer>
- </ArrayItems>
- </Expand>
- </Synthetic>
- </Expand>
- </Type>
-
-</AutoVisualizer>
diff --git a/thirdparty/ryml/src/ryml_std.hpp b/thirdparty/ryml/src/ryml_std.hpp
deleted file mode 100644
index 5e81439ac..000000000
--- a/thirdparty/ryml/src/ryml_std.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _RYML_STD_HPP_
-#define _RYML_STD_HPP_
-
-#include "./c4/yml/std/std.hpp"
-
-#endif /* _RYML_STD_HPP_ */