mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-19 06:15:46 -04:00
dep: Add rapidyaml
This commit is contained in:
282
dep/rapidyaml/include/c4/yml/common.hpp
Normal file
282
dep/rapidyaml/include/c4/yml/common.hpp
Normal file
@ -0,0 +1,282 @@
|
||||
#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 {
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
|
||||
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
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
|
||||
#endif /* _C4_YML_COMMON_HPP_ */
|
137
dep/rapidyaml/include/c4/yml/detail/parser_dbg.hpp
Normal file
137
dep/rapidyaml/include/c4/yml/detail/parser_dbg.hpp
Normal file
@ -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_ */
|
274
dep/rapidyaml/include/c4/yml/detail/stack.hpp
Normal file
274
dep/rapidyaml/include/c4/yml/detail/stack.hpp
Normal file
@ -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_ */
|
960
dep/rapidyaml/include/c4/yml/emit.def.hpp
Normal file
960
dep/rapidyaml/include/c4/yml/emit.def.hpp
Normal file
@ -0,0 +1,960 @@
|
||||
#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.capacity());
|
||||
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_ */
|
490
dep/rapidyaml/include/c4/yml/emit.hpp
Normal file
490
dep/rapidyaml/include/c4/yml/emit.hpp
Normal file
@ -0,0 +1,490 @@
|
||||
#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_ */
|
18
dep/rapidyaml/include/c4/yml/export.hpp
Normal file
18
dep/rapidyaml/include/c4/yml/export.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#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_ */
|
1280
dep/rapidyaml/include/c4/yml/node.hpp
Normal file
1280
dep/rapidyaml/include/c4/yml/node.hpp
Normal file
File diff suppressed because it is too large
Load Diff
706
dep/rapidyaml/include/c4/yml/parse.hpp
Normal file
706
dep/rapidyaml/include/c4/yml/parse.hpp
Normal file
@ -0,0 +1,706 @@
|
||||
#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_ */
|
99
dep/rapidyaml/include/c4/yml/preprocess.hpp
Normal file
99
dep/rapidyaml/include/c4/yml/preprocess.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
#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_ */
|
45
dep/rapidyaml/include/c4/yml/std/map.hpp
Normal file
45
dep/rapidyaml/include/c4/yml/std/map.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#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_
|
8
dep/rapidyaml/include/c4/yml/std/std.hpp
Normal file
8
dep/rapidyaml/include/c4/yml/std/std.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#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_
|
9
dep/rapidyaml/include/c4/yml/std/string.hpp
Normal file
9
dep/rapidyaml/include/c4/yml/std/string.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#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_
|
53
dep/rapidyaml/include/c4/yml/std/vector.hpp
Normal file
53
dep/rapidyaml/include/c4/yml/std/vector.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#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_
|
1496
dep/rapidyaml/include/c4/yml/tree.hpp
Normal file
1496
dep/rapidyaml/include/c4/yml/tree.hpp
Normal file
File diff suppressed because it is too large
Load Diff
229
dep/rapidyaml/include/c4/yml/writer.hpp
Normal file
229
dep/rapidyaml/include/c4/yml/writer.hpp
Normal file
@ -0,0 +1,229 @@
|
||||
#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_ */
|
10
dep/rapidyaml/include/c4/yml/yml.hpp
Normal file
10
dep/rapidyaml/include/c4/yml/yml.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#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_
|
Reference in New Issue
Block a user