Files
rapidyaml/api/ryml.i
2025-12-28 19:17:25 +00:00

1044 lines
36 KiB
OpenEdge ABL

%module ryml
%include "stdint.i"
//-----------------------------------------------------------------------------
// this block will be pasted verbatim in the generated C++ source file
%{
// specifies that the resulting C file should be built as a python
// extension, inserting the module init code
#define SWIG_FILE_WITH_INIT
#include <c4/yml/yml.hpp>
#include <c4/yml/error.def.hpp>
namespace c4 {
namespace yml {
using substr = c4::substr;
using csubstr = c4::csubstr;
} /* namespace yml */
} /* namespace c4 */
%}
//-----------------------------------------------------------------------------
%apply (const char *STRING, size_t LENGTH) { (const char *str, size_t len) };
%apply (char *STRING, size_t LENGTH) { (char *str, size_t len) };
%newobject emit_malloc;
%typemap(in) c4::substr {
#if defined(SWIGPYTHON)
if($input != Py_None)
{
if(PyMemoryView_Check($input)) // is it a memoryview?
{
Py_buffer const* view = PyMemoryView_GET_BUFFER($input);
$1 = c4::substr((char*)view->buf, view->len);
}
else
{
int ok = PyObject_CheckBuffer($input);
Py_buffer view;
ok = ok && (0 == PyObject_GetBuffer($input, &view, PyBUF_SIMPLE | PyBUF_WRITABLE));
if(ok)
{
$1 = c4::substr((char*)view.buf, view.len);
PyBuffer_Release(&view);
}
else
{
PyErr_SetString(PyExc_TypeError, "substr: could not get mutable memory - have you passed an imutable type such as str or bytes?");
SWIG_fail;
}
}
}
else
{
$1 = c4::substr(nullptr, size_t(0));
}
#else
#error no "in" typemap defined for this export language
#endif
};
%typemap(in) c4::csubstr {
#if defined(SWIGPYTHON)
if($input != Py_None)
{
if(PyMemoryView_Check($input)) // is it a memoryview?
{
Py_buffer const* view = PyMemoryView_GET_BUFFER($input);
$1 = c4::csubstr((const char*)view->buf, view->len);
}
else
{
Py_buffer view;
view.buf = nullptr;
int ok = PyObject_CheckBuffer($input);
ok = ok && (0 == PyObject_GetBuffer($input, &view, PyBUF_SIMPLE));
if(ok)
{
$1 = c4::csubstr((const char*)view.buf, view.len);
PyBuffer_Release(&view);
}
else
{
// https://stackoverflow.com/questions/36098984/python-3-3-c-api-and-utf-8-strings
Py_ssize_t sz = 0;
const char *buf = PyUnicode_AsUTF8AndSize($input, &sz);
if(buf || sz == 0)
{
$1 = c4::csubstr(buf, sz);
}
else
{
PyErr_SetString(PyExc_TypeError, "csubstr: could not get readonly memory from python object");
SWIG_fail;
}
}
}
}
else
{
$1 = c4::csubstr(nullptr, size_t(0));
}
#else
#error no "in" typemap defined for this export language
#endif
};
%typemap(in) csubstr = c4::csubstr;
%typemap(in) substr = c4::substr;
%typemap(in) c4::yml::csubstr = c4::csubstr;
%typemap(in) c4::yml::substr = c4::substr;
// Copy the typecheck code for "char *".
%typemap(typecheck) c4::substr = char *;
%typemap(typecheck) c4::csubstr = const char *;
//-----------------------------------------------------------------------------
%typemap(out) c4::csubstr {
#if defined(SWIGPYTHON)
if($1.str == nullptr) {
$result = Py_None;
Py_INCREF($result);
} else {
PyObject *obj = PyMemoryView_FromMemory((char*)$1.str, $1.len, PyBUF_READ);
if( ! obj)
{
PyErr_SetString(PyExc_TypeError, "could not get readonly memory from c4::csubstr - have you passed a str?");
SWIG_fail;
}
$result = obj;
}
#else
#error no "out" typemap defined for this export language
#endif
};
//-----------------------------------------------------------------------------
// Language independent exception handler.
// KEEP THIS BEFORE THE FOLLOWING FUNCTIONS!
// see https://stackoverflow.com/a/61621747
%include <std_string.i>
%include <std_except.i>
%include <exception.i>
%include <pyabc.i>
%pythonabc(c4__yml__ExceptionParse, "Exception")
%pythonabc(c4__yml__ExceptionVisit, "Exception")
%pythonabc(c4__yml__ExceptionBasic, "Exception")
%exceptionclass c4::yml::ExceptionBasic;
%exceptionclass c4::yml::ExceptionParse;
%exceptionclass c4::yml::ExceptionVisit;
%exception {
try {
$action
} catch (c4::yml::ExceptionParse const& exc) {
SWIG_Python_Raise(SWIG_NewPointerObj(
(new c4::yml::ExceptionParse(exc)),
SWIGTYPE_p_c4__yml__ExceptionParse,
SWIG_POINTER_OWN),
"ExceptionParse",
SWIGTYPE_p_c4__yml__ExceptionParse);
//std::string err = c4::yml::format_exc<std::string>(exc);
//PyErr_SetString(SWIG_Python_ExceptionType(SWIGTYPE_p_c4__yml__ExceptionParse), c4::csubstr(err.data(), err.size()), exc.errdata_parse);
SWIG_fail;
} catch (c4::yml::ExceptionVisit const& exc) {
SWIG_Python_Raise(SWIG_NewPointerObj(
(new c4::yml::ExceptionVisit(exc)),
SWIGTYPE_p_c4__yml__ExceptionVisit,
SWIG_POINTER_OWN),
"ExceptionVisit",
SWIGTYPE_p_c4__yml__ExceptionVisit);
//std::string err = c4::yml::format_exc<std::string>(exc);
//PyErr_SetString(SWIG_Python_ExceptionType(SWIGTYPE_p_c4__yml__ExceptionVisit), c4::csubstr(err.data(), err.size()), exc.errdata_visit);
SWIG_fail;
} catch (c4::yml::ExceptionBasic const& exc) {
//SWIG_exception(SWIGTYPE_p_c4__yml__ExceptionBasic, c4::csubstr(exc.str, strlen(exc.str)), exc.errdata_basic);
SWIG_Python_Raise(SWIG_NewPointerObj(
(new c4::yml::ExceptionBasic(exc)),
SWIGTYPE_p_c4__yml__ExceptionBasic,
SWIG_POINTER_OWN),
"ExceptionBasic",
SWIGTYPE_p_c4__yml__ExceptionBasic);
//std::string err = c4::yml::format_exc<std::string>(exc);
//PyErr_SetString(SWIG_Python_ExceptionType(SWIGTYPE_p_c4__yml__ExceptionBasic), c4::csubstr(err.data(), err.size()), exc.errdata_basic);
SWIG_fail;
} catch(std::exception const& e) {
SWIG_exception(SWIG_RuntimeError, e.what());
} catch(...) {
SWIG_exception(SWIG_UnknownError, "unknown error");
}
}
//-----------------------------------------------------------------------------
%inline %{
void parse_csubstr(c4::csubstr s, c4::yml::Tree *t)
{
c4::yml::parse_in_arena(s, t);
}
void parse_substr(c4::substr s, c4::yml::Tree *t)
{
c4::yml::parse_in_place(s, t);
}
char * emit_yaml_malloc(c4::yml::Tree const& t, size_t id)
{
c4::substr buf;
c4::substr ret = c4::yml::emit_yaml(t, id, buf, /*error_on_excess*/false);
if(ret.str == nullptr && ret.len > 0)
{
// Use new[]+delete[] in SWIG.
char * alloc = new char[ret.len + 1]; // we'll return a c-string and not a csubstr
c4::substr alloced_buf(alloc, ret.len);
ret = c4::yml::emit_yaml(t, id, alloced_buf, /*error_on_excess*/true);
ret.str[ret.len] = 0;
}
return ret.str;
}
char * emit_json_malloc(c4::yml::Tree const& t, size_t id)
{
c4::substr buf;
c4::substr ret = c4::yml::emit_json(t, id, buf, /*error_on_excess*/false);
if(ret.str == nullptr && ret.len > 0)
{
// Use new[]+delete[] in SWIG.
char * alloc = new char[ret.len + 1]; // we'll return a c-string and not a csubstr
c4::substr alloced_buf(alloc, ret.len);
ret = c4::yml::emit_json(t, id, alloced_buf, /*error_on_excess*/true);
ret.str[ret.len] = 0;
}
return ret.str;
}
size_t _compute_yaml_length(const c4::yml::Tree &t, size_t id)
{
c4::substr buf = {};
c4::substr ret = c4::yml::emit_yaml(t, id, buf, /*error_on_excess*/false);
return ret.len;
}
size_t _compute_json_length(const c4::yml::Tree &t, size_t id)
{
c4::substr buf = {};
c4::substr ret = c4::yml::emit_json(t, id, buf, /*error_on_excess*/false);
return ret.len;
}
bool emit_yaml_to_substr(const c4::yml::Tree &t, size_t id, c4::substr s, size_t *OUTPUT)
{
c4::substr result = c4::yml::emit_yaml(t, id, s, /*error_on_excess*/false);
*OUTPUT = result.len;
return result.str == nullptr;
}
bool emit_json_to_substr(const c4::yml::Tree &t, size_t id, c4::substr s, size_t *OUTPUT)
{
c4::substr result = c4::yml::emit_json(t, id, s, /*error_on_excess*/false);
*OUTPUT = result.len;
return result.str == nullptr;
}
// force a roundtrip to C++, which triggers a conversion to csubstr and returns it as a memoryview
c4::csubstr _get_as_csubstr(c4::csubstr s)
{
//printf("_get_as_csubstr: %p[%zu]'%.*s'\n", s.str, s.len, (int)s.len, s.str);
return s;
}
c4::csubstr _get_as_substr(c4::substr s)
{
//printf("_get_as_substr: %p[%zu]'%.*s'\n", s.str, s.len, (int)s.len, s.str);
return s;
}
// helper for calling to_arena()
c4::csubstr _to_arena_buf_cpp(c4::yml::Tree &t, c4::csubstr s)
{
return t.to_arena(s);
}
// utilities for testing
bool _same_ptr(c4::csubstr l, c4::csubstr r)
{
return l.str == r.str;
}
bool _same_mem(c4::csubstr l, c4::csubstr r)
{
return l.str == r.str && l.len == r.len;
}
%}
//-----------------------------------------------------------------------------
%pythoncode %{
from deprecation import deprecated
def as_csubstr(s):
"""return as a ryml::csubstr"""
if isinstance(s, memoryview):
return s
return _get_as_csubstr(s)
def as_substr(s):
"""return as a ryml::ssubstr"""
if isinstance(s, memoryview):
return s
return _get_as_substr(s)
def u(memview):
"""return memview as a utf8"""
return str(memview, "utf8")
def children(tree, node=None):
"""walk (non-recursively) the children of a node"""
assert tree is not None
if node is None:
node = tree.root_id()
ch = tree.first_child(node)
while ch != NONE:
yield ch
ch = tree.next_sibling(ch)
def siblings(tree, node):
"""walk (non-recursively) the siblings of a node"""
assert tree is not None
if node is None:
return
ch = tree.first_sibling(node)
while ch != NONE:
yield ch
ch = tree.next_sibling(ch)
def walk(tree, node=None, depth=0):
"""walk recursively starting at a node, returning a tuple of node and depth"""
assert tree is not None
if node is None:
node = tree.root_id()
yield node, depth
ch = tree.first_child(node)
while ch != NONE:
for gc, il in walk(tree, ch, depth + 1):
yield gc, il
ch = tree.next_sibling(ch)
@deprecated(deprecated_in="0.5.0", details="Use parse_in_arena() instead")
def parse(buf, **kwargs):
return parse_in_arena(tree, id)
def parse_in_arena(buf, tree=None):
"""
parse immutable YAML in the trees arena. Copy the YAML into a buffer
in the C++ tree's arena, then parse the YAML from the trees arena.
:param buf:
the YAML buffer to be parsed
:type buf: ``str``, ``bytes``, ``bytearray`` or ``memoryview``
:param tree:
a tree to be reused. When no tree is given, a new tree is created,
and returned at the end.
:type buf: ``ryml.Tree``
"""
if tree is None:
tree = Tree()
parse_csubstr(buf, tree)
return tree
def parse_in_place(buf, tree=None):
"""
parse in place a mutable buffer containing YAML. The resulting tree
will point into the given buffer.
:param buf:
the YAML buffer to be parsed
:type buf:
``bytearray`` or ``memoryview`` (NOT ``str`` or ``bytes``, which are not writeable)
:param tree:
a tree to be reused. When no tree is given, a new tree is created,
and returned at the end.
:type buf: ``ryml.Tree``
"""
if tree is None:
tree = Tree()
parse_substr(buf, tree)
return tree
@deprecated(deprecated_in="0.5.0", details="Use emit_yaml() instead")
def emit(tree, id=None):
return emit_yaml(tree, id)
def emit_yaml(tree, id=None):
"""emit the given tree as YAML, creating a new output buffer"""
if id is None:
id = tree.root_id()
return emit_yaml_malloc(tree, id)
def emit_json(tree, id=None):
"""emit the given tree as JSON, creating a new output buffer"""
if id is None:
id = tree.root_id()
return emit_json_malloc(tree, id)
def emit_yaml_in_place(tree, buf, id=None):
return _emit_fn_in_place(tree, buf, id, emit_yaml_to_substr)
def emit_json_in_place(tree, buf, id=None):
return _emit_fn_in_place(tree, buf, id, emit_json_to_substr)
@deprecated(deprecated_in="0.5.0", details="Use emit_yaml_in_place() instead")
def emit_in_place(tree, buf, id=None):
return emit_yaml_in_place(tree, buf, id)
def _emit_fn_in_place(tree, buf, id, fn):
if id is None:
id = tree.root_id()
(failed, expected_size) = fn(tree, id, buf)
if failed:
raise IndexError("Output buffer has {} bytes, but emit requires {} bytes".format(
len(buf), expected_size))
return memoryview(buf)[:expected_size]
def compute_yaml_length(tree, id=None):
if id is None:
id = tree.root_id()
return _compute_yaml_length(tree, id)
def compute_json_length(tree, id=None):
if id is None:
id = tree.root_id()
return _compute_json_length(tree, id)
@deprecated(deprecated_in="0.5.0", details="Use compute_yaml_length() instead")
def compute_emit_length(tree, id=None):
return compute_yaml_length(tree, id)
@deprecated(deprecated_in="0.11.0", details="Use compute_yaml_length() instead")
def compute_emit_yaml_length(tree, id=None):
return compute_yaml_length(tree, id)
@deprecated(deprecated_in="0.11.0", details="Use compute_json_length() instead")
def compute_emit_json_length(tree, id=None):
return compute_json_length(tree, id)
%}
//-----------------------------------------------------------------------------
namespace c4 {
namespace yml {
constexpr const size_t NONE = (size_t)-1;
using type_bits = uint32_t;
struct Location
{
size_t offset; ///< number of bytes from the beginning of the source buffer
size_t line;
size_t col;
c4::yml::csubstr name;
};
struct ErrorDataBasic
{
c4::yml::Location location; ///< location where the error was detected (may be from YAML or C++ source code)
ErrorDataBasic() noexcept = default;
ErrorDataBasic(c4::yml::Location const& cpploc_) noexcept;
};
struct ErrorDataParse
{
c4::yml::Location cpploc; ///< location in the C++ source file where the error was detected.
c4::yml::Location ymlloc; ///< location in the YAML source buffer where the error was detected.
ErrorDataParse() noexcept = default;
ErrorDataParse(c4::yml::Location const& cpploc_, c4::yml::Location const& ymlloc_) noexcept;
};
struct ErrorDataVisit
{
c4::yml::Location cpploc; ///< location in the C++ source file where the error was detected.
c4::yml::Tree const* tree; ///< tree where the error was detected
c4::yml::id_type node; ///< node where the error was detected
ErrorDataVisit() noexcept = default;
ErrorDataVisit(c4::yml::Location const& cpploc_, c4::yml::Tree const *tree_ , c4::yml::id_type node_) noexcept;
};
struct ExceptionBasic : public std::exception
{
ExceptionBasic(c4::yml::csubstr msg, c4::yml::ErrorDataBasic const& errdata_) noexcept;
const char* what() const noexcept override { return msg; }
c4::yml::ErrorDataBasic errdata_basic; ///< error data
char msg[RYML_ERRMSG_SIZE]; ///< the reported error message, without location indication.
};
struct ExceptionParse : public ExceptionBasic
{
ExceptionParse(c4::yml::csubstr msg, c4::yml::ErrorDataParse const& errdata_) noexcept;
c4::yml::ErrorDataParse errdata_parse;
};
struct ExceptionVisit : public ExceptionBasic
{
ExceptionVisit(c4::yml::csubstr msg, c4::yml::ErrorDataVisit const& errdata_) noexcept;
c4::yml::ErrorDataVisit errdata_visit;
};
typedef enum : c4::yml::type_bits {
NOTYPE = 0, ///< no node type or style is set
KEY = (1u << 0), ///< is member of a map
VAL = (1u << 1), ///< a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or SEQ
MAP = (1u << 2), ///< a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
SEQ = (1u << 3), ///< a seq: a parent of VAL/SEQ/MAP nodes
DOC = (1u << 4), ///< a document
STREAM = (1u << 5)|SEQ, ///< a stream: a seq of docs
KEYREF = (1u << 6), ///< a *reference: the key references an &anchor
VALREF = (1u << 7), ///< a *reference: the val references an &anchor
KEYANCH = (1u << 8), ///< the key has an &anchor
VALANCH = (1u << 9), ///< the val has an &anchor
KEYTAG = (1u << 10), ///< the key has a tag
VALTAG = (1u << 11), ///< the val has a tag
KEYNIL = (1u << 12), ///< the key is null (eg `{ : b}` results in a null key)
VALNIL = (1u << 13), ///< the val is null (eg `{a : }` results in a null val)
_TYMASK = (1u << 14)-1u, ///< all the bits up to here
//
// unfiltered flags:
//
KEY_UNFILT = (1u << 14), ///< the key scalar was left unfiltered; the parser was set not to filter. @see ParserOptions
VAL_UNFILT = (1u << 15), ///< the val scalar was left unfiltered; the parser was set not to filter. @see ParserOptions
//
// style flags:
//
FLOW_SL = (1u << 16), ///< mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,key2: val2}')
FLOW_ML = (1u << 17), ///< (NOT IMPLEMENTED, work in progress) mark container with multi-line flow style (seqs as '[\n val1,\n val2\n], maps as '{\n key: val,\n key2: val2\n}')
BLOCK = (1u << 18), ///< mark container with block style (seqs as '- val\n', maps as 'key: val')
KEY_LITERAL = (1u << 19), ///< mark key scalar as multiline, block literal |
VAL_LITERAL = (1u << 20), ///< mark val scalar as multiline, block literal |
KEY_FOLDED = (1u << 21), ///< mark key scalar as multiline, block folded >
VAL_FOLDED = (1u << 22), ///< mark val scalar as multiline, block folded >
KEY_SQUO = (1u << 23), ///< mark key scalar as single quoted '
VAL_SQUO = (1u << 24), ///< mark val scalar as single quoted '
KEY_DQUO = (1u << 25), ///< mark key scalar as double quoted "
VAL_DQUO = (1u << 26), ///< mark val scalar as double quoted "
KEY_PLAIN = (1u << 27), ///< mark key scalar as plain scalar (unquoted, even when multiline)
VAL_PLAIN = (1u << 28), ///< mark val scalar as plain scalar (unquoted, even when multiline)
//
// type combination masks:
//
KEYVAL = KEY|VAL,
KEYSEQ = KEY|SEQ,
KEYMAP = KEY|MAP,
DOCMAP = DOC|MAP,
DOCSEQ = DOC|SEQ,
DOCVAL = DOC|VAL,
//
// style combination masks:
//
SCALAR_LITERAL = KEY_LITERAL|VAL_LITERAL,
SCALAR_FOLDED = KEY_FOLDED|VAL_FOLDED,
SCALAR_SQUO = KEY_SQUO|VAL_SQUO,
SCALAR_DQUO = KEY_DQUO|VAL_DQUO,
SCALAR_PLAIN = KEY_PLAIN|VAL_PLAIN,
KEYQUO = KEY_SQUO|KEY_DQUO|KEY_FOLDED|KEY_LITERAL, ///< key style is one of ', ", > or |
VALQUO = VAL_SQUO|VAL_DQUO|VAL_FOLDED|VAL_LITERAL, ///< val style is one of ', ", > or |
KEY_STYLE = KEY_LITERAL|KEY_FOLDED|KEY_SQUO|KEY_DQUO|KEY_PLAIN, ///< mask of all the scalar styles for key (not container styles!)
VAL_STYLE = VAL_LITERAL|VAL_FOLDED|VAL_SQUO|VAL_DQUO|VAL_PLAIN, ///< mask of all the scalar styles for val (not container styles!)
SCALAR_STYLE = KEY_STYLE|VAL_STYLE,
CONTAINER_STYLE_FLOW = FLOW_SL|FLOW_ML,
CONTAINER_STYLE_BLOCK = BLOCK,
CONTAINER_STYLE = FLOW_SL|FLOW_ML|BLOCK,
STYLE = SCALAR_STYLE | CONTAINER_STYLE,
//
// mixed masks
_KEYMASK = KEY | KEYQUO | KEYANCH | KEYREF | KEYTAG,
_VALMASK = VAL | VALQUO | VALANCH | VALREF | VALTAG,
} NodeType_e;
constexpr NodeType_e operator| (NodeType_e lhs, NodeType_e rhs) noexcept;
constexpr NodeType_e operator& (NodeType_e lhs, NodeType_e rhs) noexcept;
constexpr NodeType_e operator>> (NodeType_e bits, uint32_t n) noexcept;
constexpr NodeType_e operator<< (NodeType_e bits, uint32_t n) noexcept;
constexpr NodeType_e operator~ (NodeType_e bits) noexcept;
NodeType_e& operator&= (NodeType_e &subject, NodeType_e bits) noexcept;
NodeType_e& operator|= (NodeType_e &subject, NodeType_e bits) noexcept;
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
struct NodeType
{
public:
NodeType_e type;
public:
NodeType() noexcept;
NodeType(NodeType_e t) noexcept;
NodeType(type_bits t) noexcept;
bool has_any(NodeType_e t) const noexcept;
bool has_all(NodeType_e t) const noexcept;
bool has_none(NodeType_e t) const noexcept;
void set(NodeType_e t) noexcept;
void add(NodeType_e t) noexcept;
void rem(NodeType_e t) noexcept;
void addrem(NodeType_e bits_to_add, NodeType_e bits_to_remove) noexcept;
void clear() noexcept;
public:
/** @name node type queries
* @{ */
/** return a preset string based on the node type */
const char *type_str() const noexcept;
/** return a preset string based on the node type */
static const char* type_str(NodeType_e t) noexcept;
/** fill a string with the node type flags. If the string is small, returns {null, len} */
c4::csubstr type_str(c4::substr buf) const noexcept;
/** fill a string with the node type flags. If the string is small, returns {null, len} */
static c4::csubstr type_str(c4::substr buf, NodeType_e t) noexcept;
public:
/** @name node type queries
* @{ */
bool is_notype() const noexcept;
bool is_stream() const noexcept;
bool is_doc() const noexcept;
bool is_container() const noexcept;
bool is_map() const noexcept;
bool is_seq() const noexcept;
bool has_key() const noexcept;
bool has_val() const noexcept;
bool is_val() const noexcept;
bool is_keyval() const noexcept;
bool key_is_null() const noexcept;
bool val_is_null() const noexcept;
bool has_key_tag() const noexcept;
bool has_val_tag() const noexcept;
bool has_key_anchor() const noexcept;
bool has_val_anchor() const noexcept;
bool has_anchor() const noexcept;
bool is_key_ref() const noexcept;
bool is_val_ref() const noexcept;
bool is_ref() const noexcept;
bool is_key_unfiltered() const noexcept;
bool is_val_unfiltered() const noexcept;
/** @} */
public:
/** @name container+scalar style queries
* @{ */
bool is_container_styled() const noexcept;
bool is_block() const noexcept;
bool is_flow_sl() const noexcept;
bool is_flow_ml() const noexcept;
bool is_flow() const noexcept;
bool is_key_styled() const noexcept;
bool is_val_styled() const noexcept;
bool is_key_literal() const noexcept;
bool is_val_literal() const noexcept;
bool is_key_folded() const noexcept;
bool is_val_folded() const noexcept;
bool is_key_squo() const noexcept;
bool is_val_squo() const noexcept;
bool is_key_dquo() const noexcept;
bool is_val_dquo() const noexcept;
bool is_key_plain() const noexcept;
bool is_val_plain() const noexcept;
bool is_key_quoted() const noexcept;
bool is_val_quoted() const noexcept;
bool is_quoted() const noexcept;
void set_container_style(NodeType_e style) noexcept;
void set_key_style(NodeType_e style) noexcept;
void set_val_style(NodeType_e style) noexcept;
/** @} */
};
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
#ifndef RYML_ID_TYPE
/** The type of a node id in the YAML tree. In the future, the default
* will likely change to int32_t, which was observed to be faster.
* @see id_type */
#define RYML_ID_TYPE size_t
#endif
/** The type of a node id in the YAML tree; to override the default
* type, define the macro @ref RYML_ID_TYPE to a suitable integer
* type. */
using id_type = RYML_ID_TYPE;
struct Tree
{
Tree();
Tree(id_type node_type, size_t arena_capacity=RYML_DEFAULT_TREE_ARENA_CAPACITY);
~Tree();
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY);
void reserve_arena(size_t arena_capacity=RYML_DEFAULT_TREE_ARENA_CAPACITY);
void clear();
void clear_arena();
bool empty() const;
id_type size() const;
id_type capacity() const;
id_type slack() const;
size_t arena_size() const;
size_t arena_capacity() const;
size_t arena_slack() const;
void resolve();
public:
// getters
NodeType_e type(id_type node) const;
const char* type_str(id_type node) const;
c4::csubstr key (id_type node) const;
c4::csubstr key_tag (id_type node) const;
c4::csubstr key_ref (id_type node) const;
c4::csubstr key_anchor(id_type node) const;
c4::yml::NodeScalar keysc(id_type node) const;
c4::csubstr val (id_type node) const;
c4::csubstr val_tag (id_type node) const;
c4::csubstr val_ref (id_type node) const;
c4::csubstr val_anchor(id_type node) const;
c4::yml::NodeScalar valsc(id_type node) const;
public:
// node predicates
bool type_has_any(id_type node, NodeType_e bits) const;
bool type_has_all(id_type node, NodeType_e bits) const;
bool type_has_none(id_type node, NodeType_e bits) const;
bool is_stream(id_type node) const;
bool is_doc(id_type node) const;
bool is_container(id_type node) const;
bool is_map(id_type node) const;
bool is_seq(id_type node) const;
bool has_key(id_type node) const;
bool has_val(id_type node) const;
bool is_val(id_type node) const;
bool is_keyval(id_type node) const;
bool has_key_tag(id_type node) const;
bool has_val_tag(id_type node) const;
bool has_key_anchor(id_type node) const;
bool has_val_anchor(id_type node) const;
bool has_anchor(id_type node) const;
bool is_key_ref(id_type node) const;
bool is_val_ref(id_type node) const;
bool is_ref(id_type node) const;
bool parent_is_seq(id_type node) const;
bool parent_is_map(id_type node) const;
bool has_anchor(id_type node, c4::csubstr a) const;
bool key_is_null(id_type node) const;
bool val_is_null(id_type node) const;
public:
// hierarchy predicates
bool is_root(id_type node) const;
bool has_parent(id_type node) const;
bool has_child(id_type node, c4::csubstr key) const;
//bool has_child(id_type node, id_type ch) const;
bool has_children(id_type node) const;
bool has_sibling(id_type node, c4::csubstr key) const;
//bool has_sibling(id_type node, id_type sib) const;
bool has_other_siblings(id_type node) const;
public:
// hierarchy getters
id_type root_id() const;
id_type parent(id_type node) const;
id_type prev_sibling(id_type node) const;
id_type next_sibling(id_type node) const;
id_type num_children(id_type node) const;
id_type child_pos(id_type node, id_type ch) const;
id_type first_child(id_type node) const;
id_type last_child(id_type node) const;
id_type child(id_type node, id_type pos) const;
id_type find_child(id_type node, c4::csubstr key) const;
id_type num_siblings(id_type node) const;
id_type num_other_siblings(id_type node) const;
id_type sibling_pos(id_type node, id_type sib) const;
id_type first_sibling(id_type node) const;
id_type last_sibling(id_type node) const;
id_type sibling(id_type node, id_type pos) const;
id_type find_sibling(id_type node, c4::csubstr key) const;
public:
/** @name node style predicates and modifiers. see the corresponding predicate in NodeType */
/** @{ */
bool is_container_styled(id_type node) const;
bool is_block(id_type node) const;
bool is_flow_sl(id_type node) const;
bool is_flow_ml(id_type node) const;
bool is_flow(id_type node) const;
bool is_key_styled(id_type node) const;
bool is_val_styled(id_type node) const;
bool is_key_literal(id_type node) const;
bool is_val_literal(id_type node) const;
bool is_key_folded(id_type node) const;
bool is_val_folded(id_type node) const;
bool is_key_squo(id_type node) const;
bool is_val_squo(id_type node) const;
bool is_key_dquo(id_type node) const;
bool is_val_dquo(id_type node) const;
bool is_key_plain(id_type node) const;
bool is_val_plain(id_type node) const;
bool is_key_quoted(id_type node) const;
bool is_val_quoted(id_type node) const;
bool is_quoted(id_type node) const;
void set_container_style(id_type node, NodeType_e style);
void set_key_style(id_type node, NodeType_e style);
void set_val_style(id_type node, NodeType_e style);
/** @} */
public:
void set_key_tag(id_type node, c4::csubstr tag);
void set_key_anchor(id_type node, c4::csubstr anchor);
void set_val_anchor(id_type node, c4::csubstr anchor);
void set_key_ref (id_type node, c4::csubstr ref );
void set_val_ref (id_type node, c4::csubstr ref );
void set_val_tag(id_type node, c4::csubstr tag);
void rem_key_anchor(id_type node);
void rem_val_anchor(id_type node);
void rem_key_ref (id_type node);
void rem_val_ref (id_type node);
void rem_anchor_ref(id_type node);
// these functions do not work correctly with the typemape for csubstr:
//void to_keyval(id_type node, c4::csubstr key, c4::csubstr val, int more_flags=0);
//void to_map(id_type node, c4::csubstr key, int more_flags=0);
//void to_seq(id_type node, c4::csubstr key, int more_flags=0);
//void to_val(id_type node, c4::csubstr val, int more_flags=0);
//void to_stream(id_type node, int more_flags=0);
//void to_map(id_type node, int more_flags=0);
//void to_seq(id_type node, int more_flags=0);
//void to_doc(id_type node, int more_flags=0);
//void _set_key(id_type node, c4::csubstr key, int more_flags=0);
//void _set_val(id_type node, c4::csubstr val, int more_flags=0);
//
// so we do the following:
%extend {
void _to_val(id_type node, c4::csubstr s, int flags) { $self->to_val(node, s, flags); }
void _to_keyval(id_type node, c4::csubstr key, c4::csubstr val, int more_flags) { $self->to_keyval(node, key, val, more_flags); }
void _to_map0(id_type node, int more_flags) { $self->to_map(node, more_flags); }
void _to_seq0(id_type node, int more_flags) { $self->to_seq(node, more_flags); }
void _to_map1(id_type node, c4::csubstr key, int more_flags) { $self->to_map(node, key, more_flags); }
void _to_seq1(id_type node, c4::csubstr key, int more_flags) { $self->to_seq(node, key, more_flags); }
void __set_key(id_type node, c4::csubstr key, int more_flags) { $self->_set_key(node, key, more_flags); }
void __set_val(id_type node, c4::csubstr val, int more_flags) { $self->_set_val(node, val, more_flags); }
void _to_stream(id_type node, int more_flags) { $self->to_stream(node, more_flags); }
void _to_doc(id_type node, int more_flags) { $self->to_doc(node, more_flags); }
%pythoncode %{
# this is needed to ensure the csubstr typemap applies to the overloads
def to_val(self, node, val, more_flags=0):
self._to_val(node, val, more_flags)
def to_keyval(self, node, key, val, more_flags=0):
self._to_keyval(node, key, val, more_flags)
def to_map(self, node, key=None, more_flags=0):
if isinstance(key, int):
self._to_map0(node, key | more_flags)
elif key is None:
self._to_map0(node, more_flags)
else:
self._to_map1(node, key, more_flags)
def to_seq(self, node, key=None, more_flags=0):
if isinstance(key, int):
self._to_seq0(node, key | more_flags)
elif key is None:
self._to_seq0(node, more_flags)
else:
self._to_seq1(node, key, more_flags)
def _set_key(self, node, key, more_flags=0):
self.__set_key(node, key, more_flags)
def _set_val(self, node, val, more_flags=0):
self.__set_val(node, val, more_flags)
def to_stream(self, node, more_flags=0):
self._to_stream(node, more_flags)
def to_doc(self, node, more_flags=0):
self._to_doc(node, more_flags)
%}
}
public:
/** create and insert a new child of "parent". insert after the (to-be)
* sibling "after", which must be a child of "parent". To insert as the
* first child, set after to NONE */
id_type insert_child(id_type parent, id_type after);
id_type prepend_child(id_type parent);
id_type append_child(id_type parent);
public:
//! create and insert a new sibling of n. insert after "after"
id_type insert_sibling(id_type node, id_type after);
id_type prepend_sibling(id_type node);
id_type append_sibling(id_type node);
public:
//! remove an entire branch at once: ie remove the children and the node itself
void remove(id_type node);
//! remove all the node's children, but keep the node itself
void remove_children(id_type node);
public:
void reorder();
/** change the node's position in the parent */
void move(id_type node, id_type after);
/** change the node's parent and position */
void move(id_type node, id_type new_parent, id_type after);
/** change the node's parent and position */
id_type move(Tree * src, id_type node, id_type new_parent, id_type after);
/** recursively duplicate the node */
id_type duplicate(id_type node, id_type new_parent, id_type after);
/** recursively duplicate a node from a different tree */
id_type duplicate(Tree const* src, id_type node, id_type new_parent, id_type after);
/** recursively duplicate the node's children (but not the node) */
void duplicate_children(id_type node, id_type parent, id_type after);
/** recursively duplicate the node's children (but not the node), where the node is from a different tree */
void duplicate_children(Tree const* src, id_type node, id_type parent, id_type after);
void duplicate_contents(id_type node, id_type where);
/** duplicate the node's children (but not the node) in a new parent, but
* omit repetitions where a duplicated node has the same key (in maps) or
* value (in seqs). If one of the duplicated children has the same key
* (in maps) or value (in seqs) as one of the parent's children, the one
* that is placed closest to the end will prevail. */
void duplicate_children_no_rep(id_type node, id_type parent, id_type after);
public:
%extend {
// to_arena() is a template. We use an overload set instead, as it
// will let SWIG generate the appropriate dispatch code for us.
c4::csubstr _to_arena_fundamental(uint8_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(int8_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(uint16_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(int16_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(uint32_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(int32_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(uint64_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(int64_t val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(float val) { return $self->to_arena(val); }
c4::csubstr _to_arena_fundamental(double val) { return $self->to_arena(val); }
c4::csubstr _to_arena_null() { return $self->to_arena(nullptr); }
c4::csubstr _to_arena_buffer(c4::csubstr buf) { return $self->to_arena(buf); }
%pythoncode %{
def to_arena(self, val):
if isinstance(val, (str, bytes, bytearray, memoryview)):
return _to_arena_buf_cpp(self, as_csubstr(val))
elif val is None:
return self._to_arena_null()
else:
return self._to_arena_fundamental(val)
%}
}
};
} // namespace yml
} // namespace c4