duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

emit.hpp (15910B)


      1 #ifndef _C4_YML_EMIT_HPP_
      2 #define _C4_YML_EMIT_HPP_
      3 
      4 #ifndef _C4_YML_WRITER_HPP_
      5 #include "./writer.hpp"
      6 #endif
      7 
      8 #ifndef _C4_YML_TREE_HPP_
      9 #include "./tree.hpp"
     10 #endif
     11 
     12 #ifndef _C4_YML_NODE_HPP_
     13 #include "./node.hpp"
     14 #endif
     15 
     16 
     17 #define RYML_DEPRECATE_EMIT                                             \
     18     RYML_DEPRECATED("use emit_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
     19 #ifdef emit
     20 #error "emit is defined, likely from a Qt include. This will cause a compilation error. See https://github.com/biojppm/rapidyaml/issues/120"
     21 #endif
     22 #define RYML_DEPRECATE_EMITRS                                           \
     23     RYML_DEPRECATED("use emitrs_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
     24 
     25 
     26 //-----------------------------------------------------------------------------
     27 //-----------------------------------------------------------------------------
     28 //-----------------------------------------------------------------------------
     29 
     30 namespace c4 {
     31 namespace yml {
     32 
     33 template<class Writer> class Emitter;
     34 
     35 template<class OStream>
     36 using EmitterOStream = Emitter<WriterOStream<OStream>>;
     37 using EmitterFile = Emitter<WriterFile>;
     38 using EmitterBuf  = Emitter<WriterBuf>;
     39 
     40 typedef enum {
     41     EMIT_YAML = 0,
     42     EMIT_JSON = 1
     43 } EmitType_e;
     44 
     45 
     46 /** mark a tree or node to be emitted as json */
     47 struct as_json
     48 {
     49     Tree const* tree;
     50     size_t node;
     51     as_json(Tree const& t) : tree(&t), node(t.empty() ? NONE : t.root_id()) {}
     52     as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
     53     as_json(ConstNodeRef const& n) : tree(n.tree()), node(n.id()) {}
     54 };
     55 
     56 
     57 //-----------------------------------------------------------------------------
     58 //-----------------------------------------------------------------------------
     59 //-----------------------------------------------------------------------------
     60 
     61 template<class Writer>
     62 class Emitter : public Writer
     63 {
     64 public:
     65 
     66     using Writer::Writer;
     67 
     68     /** emit!
     69      *
     70      * When writing to a buffer, returns a substr of the emitted YAML.
     71      * If the given buffer has insufficient space, the returned span will
     72      * be null and its size will be the needed space. No writes are done
     73      * after the end of the buffer.
     74      *
     75      * When writing to a file, the returned substr will be null, but its
     76      * length will be set to the number of bytes written. */
     77     substr emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);
     78     /** emit starting at the root node */
     79     substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true);
     80     /** emit the given node */
     81     substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true);
     82 
     83 private:
     84 
     85     Tree const* C4_RESTRICT m_tree;
     86 
     87     void _emit_yaml(size_t id);
     88     void _do_visit_flow_sl(size_t id, size_t ilevel=0);
     89     void _do_visit_flow_ml(size_t id, size_t ilevel=0, size_t do_indent=1);
     90     void _do_visit_block(size_t id, size_t ilevel=0, size_t do_indent=1);
     91     void _do_visit_block_container(size_t id, size_t next_level, size_t do_indent);
     92     void _do_visit_json(size_t id);
     93 
     94 private:
     95 
     96     void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t level);
     97     void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);
     98 
     99     void _write_doc(size_t id);
    100     void _write_scalar(csubstr s, bool was_quoted);
    101     void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);
    102     void _write_scalar_literal(csubstr s, size_t level, bool as_key, bool explicit_indentation=false);
    103     void _write_scalar_folded(csubstr s, size_t level, bool as_key);
    104     void _write_scalar_squo(csubstr s, size_t level);
    105     void _write_scalar_dquo(csubstr s, size_t level);
    106     void _write_scalar_plain(csubstr s, size_t level);
    107 
    108     void _write_tag(csubstr tag)
    109     {
    110         if(!tag.begins_with('!'))
    111             this->Writer::_do_write('!');
    112         this->Writer::_do_write(tag);
    113     }
    114 
    115     enum : type_bits {
    116         _keysc =  (KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
    117         _valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) |  (VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
    118         _keysc_json =  (KEY)  | ~(VAL),
    119         _valsc_json = ~(KEY)  |  (VAL),
    120     };
    121 
    122     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); }
    123     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); }
    124 
    125     C4_ALWAYS_INLINE void _writek_json(size_t id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
    126     C4_ALWAYS_INLINE void _writev_json(size_t id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
    127 
    128 };
    129 
    130 
    131 //-----------------------------------------------------------------------------
    132 //-----------------------------------------------------------------------------
    133 //-----------------------------------------------------------------------------
    134 
    135 /** emit YAML to the given file. A null file defaults to stdout.
    136  * Return the number of bytes written. */
    137 inline size_t emit_yaml(Tree const& t, size_t id, FILE *f)
    138 {
    139     EmitterFile em(f);
    140     return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
    141 }
    142 RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, size_t id, FILE *f)
    143 {
    144     return emit_yaml(t, id, f);
    145 }
    146 
    147 /** emit JSON to the given file. A null file defaults to stdout.
    148  * Return the number of bytes written. */
    149 inline size_t emit_json(Tree const& t, size_t id, FILE *f)
    150 {
    151     EmitterFile em(f);
    152     return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
    153 }
    154 
    155 
    156 /** emit YAML to the given file. A null file defaults to stdout.
    157  * Return the number of bytes written.
    158  * @overload */
    159 inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
    160 {
    161     EmitterFile em(f);
    162     return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
    163 }
    164 RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
    165 {
    166     return emit_yaml(t, f);
    167 }
    168 
    169 /** emit JSON to the given file. A null file defaults to stdout.
    170  * Return the number of bytes written.
    171  * @overload */
    172 inline size_t emit_json(Tree const& t, FILE *f=nullptr)
    173 {
    174     EmitterFile em(f);
    175     return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
    176 }
    177 
    178 
    179 /** emit YAML to the given file. A null file defaults to stdout.
    180  * Return the number of bytes written.
    181  * @overload */
    182 inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
    183 {
    184     EmitterFile em(f);
    185     return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
    186 }
    187 RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
    188 {
    189     return emit_yaml(r, f);
    190 }
    191 
    192 /** emit JSON to the given file. A null file defaults to stdout.
    193  * Return the number of bytes written.
    194  * @overload */
    195 inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
    196 {
    197     EmitterFile em(f);
    198     return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
    199 }
    200 
    201 
    202 //-----------------------------------------------------------------------------
    203 
    204 /** emit YAML to an STL-like ostream */
    205 template<class OStream>
    206 inline OStream& operator<< (OStream& s, Tree const& t)
    207 {
    208     EmitterOStream<OStream> em(s);
    209     em.emit_as(EMIT_YAML, t);
    210     return s;
    211 }
    212 
    213 /** emit YAML to an STL-like ostream
    214  * @overload */
    215 template<class OStream>
    216 inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
    217 {
    218     EmitterOStream<OStream> em(s);
    219     em.emit_as(EMIT_YAML, n);
    220     return s;
    221 }
    222 
    223 /** emit json to an STL-like stream */
    224 template<class OStream>
    225 inline OStream& operator<< (OStream& s, as_json const& j)
    226 {
    227     EmitterOStream<OStream> em(s);
    228     em.emit_as(EMIT_JSON, *j.tree, j.node, true);
    229     return s;
    230 }
    231 
    232 
    233 //-----------------------------------------------------------------------------
    234 
    235 
    236 /** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
    237  * @param error_on_excess Raise an error if the space in the buffer is insufficient.
    238  * @overload */
    239 inline substr emit_yaml(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
    240 {
    241     EmitterBuf em(buf);
    242     return em.emit_as(EMIT_YAML, t, id, error_on_excess);
    243 }
    244 RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
    245 {
    246     return emit_yaml(t, id, buf, error_on_excess);
    247 }
    248 
    249 /** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
    250  * @param error_on_excess Raise an error if the space in the buffer is insufficient.
    251  * @overload */
    252 inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
    253 {
    254     EmitterBuf em(buf);
    255     return em.emit_as(EMIT_JSON, t, id, error_on_excess);
    256 }
    257 
    258 
    259 /** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
    260  * @param error_on_excess Raise an error if the space in the buffer is insufficient.
    261  * @overload */
    262 inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
    263 {
    264     EmitterBuf em(buf);
    265     return em.emit_as(EMIT_YAML, t, error_on_excess);
    266 }
    267 RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
    268 {
    269     return emit_yaml(t, buf, error_on_excess);
    270 }
    271 
    272 /** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
    273  * @param error_on_excess Raise an error if the space in the buffer is insufficient.
    274  * @overload */
    275 inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
    276 {
    277     EmitterBuf em(buf);
    278     return em.emit_as(EMIT_JSON, t, error_on_excess);
    279 }
    280 
    281 
    282 /** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
    283  * @param error_on_excess Raise an error if the space in the buffer is insufficient.
    284  * @overload
    285  */
    286 inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
    287 {
    288     EmitterBuf em(buf);
    289     return em.emit_as(EMIT_YAML, r, error_on_excess);
    290 }
    291 RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
    292 {
    293     return emit_yaml(r, buf, error_on_excess);
    294 }
    295 
    296 /** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
    297  * @param error_on_excess Raise an error if the space in the buffer is insufficient.
    298  * @overload
    299  */
    300 inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
    301 {
    302     EmitterBuf em(buf);
    303     return em.emit_as(EMIT_JSON, r, error_on_excess);
    304 }
    305 
    306 
    307 //-----------------------------------------------------------------------------
    308 
    309 /** emit+resize: emit YAML to the given std::string/std::vector-like
    310  * container, resizing it as needed to fit the emitted YAML. */
    311 template<class CharOwningContainer>
    312 substr emitrs_yaml(Tree const& t, size_t id, CharOwningContainer * cont)
    313 {
    314     substr buf = to_substr(*cont);
    315     substr ret = emit_yaml(t, id, buf, /*error_on_excess*/false);
    316     if(ret.str == nullptr && ret.len > 0)
    317     {
    318         cont->resize(ret.len);
    319         buf = to_substr(*cont);
    320         ret = emit_yaml(t, id, buf, /*error_on_excess*/true);
    321     }
    322     return ret;
    323 }
    324 template<class CharOwningContainer>
    325 RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
    326 {
    327     return emitrs_yaml(t, id, cont);
    328 }
    329 
    330 /** emit+resize: emit JSON to the given std::string/std::vector-like
    331  * container, resizing it as needed to fit the emitted JSON. */
    332 template<class CharOwningContainer>
    333 substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
    334 {
    335     substr buf = to_substr(*cont);
    336     substr ret = emit_json(t, id, buf, /*error_on_excess*/false);
    337     if(ret.str == nullptr && ret.len > 0)
    338     {
    339         cont->resize(ret.len);
    340         buf = to_substr(*cont);
    341         ret = emit_json(t, id, buf, /*error_on_excess*/true);
    342     }
    343     return ret;
    344 }
    345 
    346 
    347 /** emit+resize: emit YAML to the given std::string/std::vector-like
    348  * container, resizing it as needed to fit the emitted YAML. */
    349 template<class CharOwningContainer>
    350 CharOwningContainer emitrs_yaml(Tree const& t, size_t id)
    351 {
    352     CharOwningContainer c;
    353     emitrs_yaml(t, id, &c);
    354     return c;
    355 }
    356 template<class CharOwningContainer>
    357 RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, size_t id)
    358 {
    359     CharOwningContainer c;
    360     emitrs_yaml(t, id, &c);
    361     return c;
    362 }
    363 
    364 /** emit+resize: emit JSON to the given std::string/std::vector-like
    365  * container, resizing it as needed to fit the emitted JSON. */
    366 template<class CharOwningContainer>
    367 CharOwningContainer emitrs_json(Tree const& t, size_t id)
    368 {
    369     CharOwningContainer c;
    370     emitrs_json(t, id, &c);
    371     return c;
    372 }
    373 
    374 
    375 /** emit+resize: YAML to the given std::string/std::vector-like
    376  * container, resizing it as needed to fit the emitted YAML. */
    377 template<class CharOwningContainer>
    378 substr emitrs_yaml(Tree const& t, CharOwningContainer * cont)
    379 {
    380     if(t.empty())
    381         return {};
    382     return emitrs_yaml(t, t.root_id(), cont);
    383 }
    384 template<class CharOwningContainer>
    385 RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
    386 {
    387     return emitrs_yaml(t, cont);
    388 }
    389 
    390 /** emit+resize: JSON to the given std::string/std::vector-like
    391  * container, resizing it as needed to fit the emitted JSON. */
    392 template<class CharOwningContainer>
    393 substr emitrs_json(Tree const& t, CharOwningContainer * cont)
    394 {
    395     if(t.empty())
    396         return {};
    397     return emitrs_json(t, t.root_id(), cont);
    398 }
    399 
    400 
    401 /** emit+resize: YAML to the given std::string/std::vector-like container,
    402  * resizing it as needed to fit the emitted YAML. */
    403 template<class CharOwningContainer>
    404 CharOwningContainer emitrs_yaml(Tree const& t)
    405 {
    406     CharOwningContainer c;
    407     if(t.empty())
    408         return c;
    409     emitrs_yaml(t, t.root_id(), &c);
    410     return c;
    411 }
    412 template<class CharOwningContainer>
    413 RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
    414 {
    415     return emitrs_yaml<CharOwningContainer>(t);
    416 }
    417 
    418 /** emit+resize: JSON to the given std::string/std::vector-like container,
    419  * resizing it as needed to fit the emitted JSON. */
    420 template<class CharOwningContainer>
    421 CharOwningContainer emitrs_json(Tree const& t)
    422 {
    423     CharOwningContainer c;
    424     if(t.empty())
    425         return c;
    426     emitrs_json(t, t.root_id(), &c);
    427     return c;
    428 }
    429 
    430 
    431 /** emit+resize: YAML to the given std::string/std::vector-like container,
    432  * resizing it as needed to fit the emitted YAML. */
    433 template<class CharOwningContainer>
    434 substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont)
    435 {
    436     _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
    437     return emitrs_yaml(*n.tree(), n.id(), cont);
    438 }
    439 template<class CharOwningContainer>
    440 RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
    441 {
    442     return emitrs_yaml(n, cont);
    443 }
    444 
    445 /** emit+resize: JSON to the given std::string/std::vector-like container,
    446  * resizing it as needed to fit the emitted JSON. */
    447 template<class CharOwningContainer>
    448 substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)
    449 {
    450     _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
    451     return emitrs_json(*n.tree(), n.id(), cont);
    452 }
    453 
    454 
    455 /** emit+resize: YAML to the given std::string/std::vector-like container,
    456  * resizing it as needed to fit the emitted YAML. */
    457 template<class CharOwningContainer>
    458 CharOwningContainer emitrs_yaml(ConstNodeRef const& n)
    459 {
    460     _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
    461     CharOwningContainer c;
    462     emitrs_yaml(*n.tree(), n.id(), &c);
    463     return c;
    464 }
    465 template<class CharOwningContainer>
    466 RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
    467 {
    468     return emitrs_yaml<CharOwningContainer>(n);
    469 }
    470 
    471 /** emit+resize: JSON to the given std::string/std::vector-like container,
    472  * resizing it as needed to fit the emitted JSON. */
    473 template<class CharOwningContainer>
    474 CharOwningContainer emitrs_json(ConstNodeRef const& n)
    475 {
    476     _RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
    477     CharOwningContainer c;
    478     emitrs_json(*n.tree(), n.id(), &c);
    479     return c;
    480 }
    481 
    482 } // namespace yml
    483 } // namespace c4
    484 
    485 #undef RYML_DEPRECATE_EMIT
    486 #undef RYML_DEPRECATE_EMITRS
    487 
    488 #include "c4/yml/emit.def.hpp"
    489 
    490 #endif /* _C4_YML_EMIT_HPP_ */