Path: blob/master/dep/rapidyaml/include/c4/yml/emit.hpp
4264 views
#ifndef _C4_YML_EMIT_HPP_1#define _C4_YML_EMIT_HPP_23#ifndef _C4_YML_WRITER_HPP_4#include "./writer.hpp"5#endif67#ifndef _C4_YML_TREE_HPP_8#include "./tree.hpp"9#endif1011#ifndef _C4_YML_NODE_HPP_12#include "./node.hpp"13#endif141516#define RYML_DEPRECATE_EMIT \17RYML_DEPRECATED("use emit_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")18#ifdef emit19#error "emit is defined, likely from a Qt include. This will cause a compilation error. See https://github.com/biojppm/rapidyaml/issues/120"20#endif21#define RYML_DEPRECATE_EMITRS \22RYML_DEPRECATED("use emitrs_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")232425//-----------------------------------------------------------------------------26//-----------------------------------------------------------------------------27//-----------------------------------------------------------------------------2829namespace c4 {30namespace yml {3132template<class Writer> class Emitter;3334template<class OStream>35using EmitterOStream = Emitter<WriterOStream<OStream>>;36using EmitterFile = Emitter<WriterFile>;37using EmitterBuf = Emitter<WriterBuf>;3839typedef enum {40EMIT_YAML = 0,41EMIT_JSON = 142} EmitType_e;434445/** mark a tree or node to be emitted as json */46struct as_json47{48Tree const* tree;49size_t node;50as_json(Tree const& t) : tree(&t), node(t.empty() ? NONE : t.root_id()) {}51as_json(Tree const& t, size_t id) : tree(&t), node(id) {}52as_json(ConstNodeRef const& n) : tree(n.tree()), node(n.id()) {}53};545556//-----------------------------------------------------------------------------57//-----------------------------------------------------------------------------58//-----------------------------------------------------------------------------5960template<class Writer>61class Emitter : public Writer62{63public:6465using Writer::Writer;6667/** emit!68*69* When writing to a buffer, returns a substr of the emitted YAML.70* If the given buffer has insufficient space, the returned span will71* be null and its size will be the needed space. No writes are done72* after the end of the buffer.73*74* When writing to a file, the returned substr will be null, but its75* length will be set to the number of bytes written. */76substr emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);77/** emit starting at the root node */78substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true);79/** emit the given node */80substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true);8182private:8384Tree const* C4_RESTRICT m_tree;8586void _emit_yaml(size_t id);87void _do_visit_flow_sl(size_t id, size_t ilevel=0);88void _do_visit_flow_ml(size_t id, size_t ilevel=0, size_t do_indent=1);89void _do_visit_block(size_t id, size_t ilevel=0, size_t do_indent=1);90void _do_visit_block_container(size_t id, size_t next_level, size_t do_indent);91void _do_visit_json(size_t id);9293private:9495void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t level);96void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);9798void _write_doc(size_t id);99void _write_scalar(csubstr s, bool was_quoted);100void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);101void _write_scalar_literal(csubstr s, size_t level, bool as_key, bool explicit_indentation=false);102void _write_scalar_folded(csubstr s, size_t level, bool as_key);103void _write_scalar_squo(csubstr s, size_t level);104void _write_scalar_dquo(csubstr s, size_t level);105void _write_scalar_plain(csubstr s, size_t level);106107void _write_tag(csubstr tag)108{109if(!tag.begins_with('!'))110this->Writer::_do_write('!');111this->Writer::_do_write(tag);112}113114enum : type_bits {115_keysc = (KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),116_valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),117_keysc_json = (KEY) | ~(VAL),118_valsc_json = ~(KEY) | (VAL),119};120121C4_ALWAYS_INLINE void _writek(size_t id, size_t level) { _write(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~_valsc, level); }122C4_ALWAYS_INLINE void _writev(size_t id, size_t level) { _write(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~_keysc, level); }123124C4_ALWAYS_INLINE void _writek_json(size_t id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }125C4_ALWAYS_INLINE void _writev_json(size_t id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }126127};128129130//-----------------------------------------------------------------------------131//-----------------------------------------------------------------------------132//-----------------------------------------------------------------------------133134/** emit YAML to the given file. A null file defaults to stdout.135* Return the number of bytes written. */136inline size_t emit_yaml(Tree const& t, size_t id, FILE *f)137{138EmitterFile em(f);139return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;140}141RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, size_t id, FILE *f)142{143return emit_yaml(t, id, f);144}145146/** emit JSON to the given file. A null file defaults to stdout.147* Return the number of bytes written. */148inline size_t emit_json(Tree const& t, size_t id, FILE *f)149{150EmitterFile em(f);151return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;152}153154155/** emit YAML to the given file. A null file defaults to stdout.156* Return the number of bytes written.157* @overload */158inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)159{160EmitterFile em(f);161return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;162}163RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)164{165return emit_yaml(t, f);166}167168/** emit JSON to the given file. A null file defaults to stdout.169* Return the number of bytes written.170* @overload */171inline size_t emit_json(Tree const& t, FILE *f=nullptr)172{173EmitterFile em(f);174return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;175}176177178/** emit YAML to the given file. A null file defaults to stdout.179* Return the number of bytes written.180* @overload */181inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)182{183EmitterFile em(f);184return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;185}186RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)187{188return emit_yaml(r, f);189}190191/** emit JSON to the given file. A null file defaults to stdout.192* Return the number of bytes written.193* @overload */194inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)195{196EmitterFile em(f);197return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;198}199200201//-----------------------------------------------------------------------------202203/** emit YAML to an STL-like ostream */204template<class OStream>205inline OStream& operator<< (OStream& s, Tree const& t)206{207EmitterOStream<OStream> em(s);208em.emit_as(EMIT_YAML, t);209return s;210}211212/** emit YAML to an STL-like ostream213* @overload */214template<class OStream>215inline OStream& operator<< (OStream& s, ConstNodeRef const& n)216{217EmitterOStream<OStream> em(s);218em.emit_as(EMIT_YAML, n);219return s;220}221222/** emit json to an STL-like stream */223template<class OStream>224inline OStream& operator<< (OStream& s, as_json const& j)225{226EmitterOStream<OStream> em(s);227em.emit_as(EMIT_JSON, *j.tree, j.node, true);228return s;229}230231232//-----------------------------------------------------------------------------233234235/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.236* @param error_on_excess Raise an error if the space in the buffer is insufficient.237* @overload */238inline substr emit_yaml(Tree const& t, size_t id, substr buf, bool error_on_excess=true)239{240EmitterBuf em(buf);241return em.emit_as(EMIT_YAML, t, id, error_on_excess);242}243RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)244{245return emit_yaml(t, id, buf, error_on_excess);246}247248/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.249* @param error_on_excess Raise an error if the space in the buffer is insufficient.250* @overload */251inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)252{253EmitterBuf em(buf);254return em.emit_as(EMIT_JSON, t, id, error_on_excess);255}256257258/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.259* @param error_on_excess Raise an error if the space in the buffer is insufficient.260* @overload */261inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)262{263EmitterBuf em(buf);264return em.emit_as(EMIT_YAML, t, error_on_excess);265}266RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)267{268return emit_yaml(t, buf, error_on_excess);269}270271/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.272* @param error_on_excess Raise an error if the space in the buffer is insufficient.273* @overload */274inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)275{276EmitterBuf em(buf);277return em.emit_as(EMIT_JSON, t, error_on_excess);278}279280281/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.282* @param error_on_excess Raise an error if the space in the buffer is insufficient.283* @overload284*/285inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)286{287EmitterBuf em(buf);288return em.emit_as(EMIT_YAML, r, error_on_excess);289}290RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)291{292return emit_yaml(r, buf, error_on_excess);293}294295/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.296* @param error_on_excess Raise an error if the space in the buffer is insufficient.297* @overload298*/299inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)300{301EmitterBuf em(buf);302return em.emit_as(EMIT_JSON, r, error_on_excess);303}304305306//-----------------------------------------------------------------------------307308/** emit+resize: emit YAML to the given std::string/std::vector-like309* container, resizing it as needed to fit the emitted YAML. */310template<class CharOwningContainer>311substr emitrs_yaml(Tree const& t, size_t id, CharOwningContainer * cont)312{313substr buf = to_substr(*cont);314substr ret = emit_yaml(t, id, buf, /*error_on_excess*/false);315if(ret.str == nullptr && ret.len > 0)316{317cont->resize(ret.len);318buf = to_substr(*cont);319ret = emit_yaml(t, id, buf, /*error_on_excess*/true);320}321return ret;322}323template<class CharOwningContainer>324RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)325{326return emitrs_yaml(t, id, cont);327}328329/** emit+resize: emit JSON to the given std::string/std::vector-like330* container, resizing it as needed to fit the emitted JSON. */331template<class CharOwningContainer>332substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)333{334substr buf = to_substr(*cont);335substr ret = emit_json(t, id, buf, /*error_on_excess*/false);336if(ret.str == nullptr && ret.len > 0)337{338cont->resize(ret.len);339buf = to_substr(*cont);340ret = emit_json(t, id, buf, /*error_on_excess*/true);341}342return ret;343}344345346/** emit+resize: emit YAML to the given std::string/std::vector-like347* container, resizing it as needed to fit the emitted YAML. */348template<class CharOwningContainer>349CharOwningContainer emitrs_yaml(Tree const& t, size_t id)350{351CharOwningContainer c;352emitrs_yaml(t, id, &c);353return c;354}355template<class CharOwningContainer>356RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, size_t id)357{358CharOwningContainer c;359emitrs_yaml(t, id, &c);360return c;361}362363/** emit+resize: emit JSON to the given std::string/std::vector-like364* container, resizing it as needed to fit the emitted JSON. */365template<class CharOwningContainer>366CharOwningContainer emitrs_json(Tree const& t, size_t id)367{368CharOwningContainer c;369emitrs_json(t, id, &c);370return c;371}372373374/** emit+resize: YAML to the given std::string/std::vector-like375* container, resizing it as needed to fit the emitted YAML. */376template<class CharOwningContainer>377substr emitrs_yaml(Tree const& t, CharOwningContainer * cont)378{379if(t.empty())380return {};381return emitrs_yaml(t, t.root_id(), cont);382}383template<class CharOwningContainer>384RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)385{386return emitrs_yaml(t, cont);387}388389/** emit+resize: JSON to the given std::string/std::vector-like390* container, resizing it as needed to fit the emitted JSON. */391template<class CharOwningContainer>392substr emitrs_json(Tree const& t, CharOwningContainer * cont)393{394if(t.empty())395return {};396return emitrs_json(t, t.root_id(), cont);397}398399400/** emit+resize: YAML to the given std::string/std::vector-like container,401* resizing it as needed to fit the emitted YAML. */402template<class CharOwningContainer>403CharOwningContainer emitrs_yaml(Tree const& t)404{405CharOwningContainer c;406if(t.empty())407return c;408emitrs_yaml(t, t.root_id(), &c);409return c;410}411template<class CharOwningContainer>412RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)413{414return emitrs_yaml<CharOwningContainer>(t);415}416417/** emit+resize: JSON to the given std::string/std::vector-like container,418* resizing it as needed to fit the emitted JSON. */419template<class CharOwningContainer>420CharOwningContainer emitrs_json(Tree const& t)421{422CharOwningContainer c;423if(t.empty())424return c;425emitrs_json(t, t.root_id(), &c);426return c;427}428429430/** emit+resize: YAML to the given std::string/std::vector-like container,431* resizing it as needed to fit the emitted YAML. */432template<class CharOwningContainer>433substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont)434{435_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());436return emitrs_yaml(*n.tree(), n.id(), cont);437}438template<class CharOwningContainer>439RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)440{441return emitrs_yaml(n, cont);442}443444/** emit+resize: JSON to the given std::string/std::vector-like container,445* resizing it as needed to fit the emitted JSON. */446template<class CharOwningContainer>447substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)448{449_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());450return emitrs_json(*n.tree(), n.id(), cont);451}452453454/** emit+resize: YAML to the given std::string/std::vector-like container,455* resizing it as needed to fit the emitted YAML. */456template<class CharOwningContainer>457CharOwningContainer emitrs_yaml(ConstNodeRef const& n)458{459_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());460CharOwningContainer c;461emitrs_yaml(*n.tree(), n.id(), &c);462return c;463}464template<class CharOwningContainer>465RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)466{467return emitrs_yaml<CharOwningContainer>(n);468}469470/** emit+resize: JSON to the given std::string/std::vector-like container,471* resizing it as needed to fit the emitted JSON. */472template<class CharOwningContainer>473CharOwningContainer emitrs_json(ConstNodeRef const& n)474{475_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());476CharOwningContainer c;477emitrs_json(*n.tree(), n.id(), &c);478return c;479}480481} // namespace yml482} // namespace c4483484#undef RYML_DEPRECATE_EMIT485#undef RYML_DEPRECATE_EMITRS486487#include "c4/yml/emit.def.hpp"488489#endif /* _C4_YML_EMIT_HPP_ */490491492