%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 #include 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 %include %include %include %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(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(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(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