aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/ryml/src/c4/yml/detail
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-11-07 14:49:13 +0100
committerGitHub Enterprise <[email protected]>2025-11-07 14:49:13 +0100
commit24e43a913f29ac3b314354e8ce5175f135bcc64f (patch)
treeca442937ceeb63461012b33a4576e9835099f106 /thirdparty/ryml/src/c4/yml/detail
parentget oplog attachments (#622) (diff)
downloadzen-24e43a913f29ac3b314354e8ce5175f135bcc64f.tar.xz
zen-24e43a913f29ac3b314354e8ce5175f135bcc64f.zip
switch to xmake for package management (#611)
This change removes our dependency on vcpkg for package management, in favour of bringing some code in-tree in the `thirdparty` folder as well as using the xmake build-in package management feature. For the latter, all the package definitions are maintained in the zen repo itself, in the `repo` folder. It should now also be easier to build the project as it will no longer depend on having the right version of vcpkg installed, which has been a common problem for new people coming in to the codebase. Now you should only need xmake to build. * Bumps xmake requirement on github runners to 2.9.9 to resolve an issue where xmake on Windows invokes cmake with `v144` toolchain which does not exist * BLAKE3 is now in-tree at `thirdparty/blake3` * cpr is now in-tree at `thirdparty/cpr` * cxxopts is now in-tree at `thirdparty/cxxopts` * fmt is now in-tree at `thirdparty/fmt` * robin-map is now in-tree at `thirdparty/robin-map` * ryml is now in-tree at `thirdparty/ryml` * sol2 is now in-tree at `thirdparty/sol2` * spdlog is now in-tree at `thirdparty/spdlog` * utfcpp is now in-tree at `thirdparty/utfcpp` * xmake package repo definitions is in `repo` * implemented support for sanitizers. ASAN is supported on windows, TSAN, UBSAN, MSAN etc are supported on Linux/MacOS though I have not yet tested it extensively on MacOS * the zencore encryption implementation also now supports using mbedTLS which is used on MacOS, though for now we still use openssl on Linux * crashpad * bumps libcurl to 8.11.0 (from 8.8.0) which should address a rare build upload bug
Diffstat (limited to 'thirdparty/ryml/src/c4/yml/detail')
-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
4 files changed, 739 insertions, 0 deletions
diff --git a/thirdparty/ryml/src/c4/yml/detail/checks.hpp b/thirdparty/ryml/src/c4/yml/detail/checks.hpp
new file mode 100644
index 000000000..39b49e856
--- /dev/null
+++ b/thirdparty/ryml/src/c4/yml/detail/checks.hpp
@@ -0,0 +1,200 @@
+#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
new file mode 100644
index 000000000..457f1700d
--- /dev/null
+++ b/thirdparty/ryml/src/c4/yml/detail/parser_dbg.hpp
@@ -0,0 +1,137 @@
+#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
new file mode 100644
index 000000000..f88dc251d
--- /dev/null
+++ b/thirdparty/ryml/src/c4/yml/detail/print.hpp
@@ -0,0 +1,128 @@
+#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
new file mode 100644
index 000000000..95677ae27
--- /dev/null
+++ b/thirdparty/ryml/src/c4/yml/detail/stack.hpp
@@ -0,0 +1,274 @@
+#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_ */