fkYAML

repository·develop·Indexed 41 days ago

https://github.com/fktn-k/fkyaml

A portable, header-only C++11 library for serializing, deserializing, and building YAML documents. It strictly adheres to the YAML 1.2.2 specification and is designed for high performance, supporting UTF-8, UTF-16, and UTF-32 encodings, as well as tags, anchors, and aliases.

Tokens
30.6K
Snippets
123
Records
168
Agent score
99%

What's inside fkYAML

  1. Core features of fkYAML

    develop

    fkYAML provides comprehensive YAML 1.2.2 compliance and several developer-friendly features:

    YAML Compliance

    • Syntax Support: Handles scalars, sequences, and mappings in both block and flow styles. Supports sequences and mappings as keys for operator[] or at().
    • Directives: Supports %TAG and %YAML directives (unknown directives are ignored).
    • Advanced YAML: Supports tags, anchors, and aliases.
    • Document Handling: Supports single document processing via deserialize()/serialize() and multiple document processing via deserialize_docs()/serialize_docs().

    Encodings and Line Breaks

    • Encodings: Supports UTF-8, UTF-16, and UTF-32 (including little and big endian). It features automatic detection of encodings via BOM or ASCII.
    • Line Breaks: Supports both Unix (\n) and Windows (\r\n) line breaks for deserialization. Serialization defaults to Unix style (\n).

    Customization

    • Node Value Types: The storage types for scalars, sequences, and mappings in fkyaml::node are customizable via template parameters in fkyaml::basic_node.
    • Type Conversion: Provides built-in conversions for STL containers and scalars. Users can implement custom from_node and to_node functions for project-specific types.
  2. Understand the fkyaml::basic_node template

    develop

    The fkyaml::basic_node class is the foundational template used to handle YAML nodes. It is highly configurable via template parameters, allowing you to define the underlying storage types for sequences, mappings, and scalar values (booleans, integers, floats, and strings), as well as the conversion logic used between nodes and native C++ types.

    While fkyaml::basic_node is the base template, most users will interact with the node specialization, which provides a default configuration.

    template<
        template <typename, typename...> class SequenceType = std::vector,
        template <typename, typename, typename...> class MappingType = std::map,
        typename BooleanType = bool,
        typename IntegerType = std::int64_t,
        typename FloatNumberType = double,
        typename StringType = std::string,
        template <typename, typename = void> class ConverterType = node_value_converter
    >
    class basic_node;
  3. Understand the serialization format of basic_node::serialize

    develop

    The serialize function follows specific structural rules for different node types:

    Scalars

    {[anchor] [tag] value | alias}

    Sequences

    As a sequence value:

    <scalar>: [anchor] [tag]
      - <sequence scalar value>
      - [anchor] [tag]
        - <child sequence value>

    Note: 2 spaces are inserted before - indicators.

    As an explicit key node:

    ? - <sequence value>
      - <another sequence value>
    : <scalar>

    Mappings

    Value is a scalar: <scalar>: <scalar>

    Value is a container (mapping or sequence):

    <scalar>: [anchor] [tag]
      <mapping scalar key>: <mapping scalar value>
      <mapping scalar key>: [anchor] [tag]
        <child mapping scalar key>: <child mapping scalar value>

    Note: 2 spaces are inserted before the value to indicate indentation.

    As an explicit key node:

    ? <mapping>
    : <scalar>
  4. Understand fkyaml::ordered_map

    develop

    What is fkyaml::ordered_map?

    fkyaml::ordered_map is a minimal map-like container that preserves the order of insertion. It inherits from std::vector<std::pair<Key, Value>>.

    When to use it

    In YAML, mapping nodes are technically defined as unordered sets of key-value pairs. However, when working with YAML deserialization, you often need to preserve the original order of keys to ensure that re-serializing the data produces a file that matches the input.

    Using ordered_map allows you to:

    1. Maintain the exact sequence of keys as they appeared in the YAML source.
    2. Avoid the overhead and complexity of representing mappings as sequences of key-value pairs at the application layer.
    3. Ensure consistent serialization behavior.
  5. Customize to_node for user-defined types

    develop

    You can extend fkyaml to support your own custom types by implementing a (partial) specialization of the to_node() function. This allows basic_node to accept your custom objects during construction or assignment.

    Critical Requirement: The specialization must be implemented in the same namespace as your user-defined type. This ensures that the specialization is correctly located via Argument-Dependent Lookup (ADL).

    Implementation Pattern

    1. Define your custom type in a namespace.
    2. Implement the to_node specialization within that same namespace.
  6. Customize from_node for user-defined types

    develop

    You can extend from_node to support your own custom types by implementing a (partial) specialization of the ::fkyaml::from_node() function.

    Critical Implementation Rule: To ensure the specialization is found via Argument Dependent Lookup (ADL), you must implement the specialization in the same namespace as your user-defined type (or in the global namespace if the type is global).

  7. Integrate with user-defined types

    develop

    You can specialize serialization and deserialization for your own custom types by using from_node() and to_node().

    Requirements:

    • User-defined types must be default-constructible to use these specializations.
    • STL types (like std::vector or std::string) are already supported by default and do not require manual specialization.
  8. Choose the right conversion method for basic_node

    develop

    When extracting data from a fkyaml::basic_node, choose the method based on your performance and type requirements:

    • get_value<T>(): Use when you want a copy of the value in a standard C++ type (e.g., int, std::string, std::vector).
    • get_value_inplace<T>(): Use when you need to convert into a C-style array or want to avoid unnecessary copies by writing directly into existing memory.
    • as_seq(), as_map(), as_bool(), as_int(), as_float(), as_str(): Use these specialized methods if you want to avoid the overhead of template instantiation or if you need to access the underlying node structure/address directly rather than a copy.
  9. Integrate fkYAML into your C++ project

    develop

    fkYAML is a header-only library, making integration straightforward. You can incorporate it by simply including the header files in your project.

    Options for integration:

    • Standard Header-only: Copy the headers to your project and include them.
    • Single-header version: Use the single-header file located at single_include/fkYAML/node.hpp for even simpler setup.
    • Forward Declarations: Use fkyaml_fwd.hpp to provide forward declarations of the APIs, which helps reduce compilation times by avoiding unnecessary full definitions in header files.
    • CMake: The project supports CMake and provides specific documentation for CMake integration.
  10. Preserve insertion order of key-value pairs

    develop

    To ensure that the order in which key-value pairs are inserted is maintained (overriding the default std::map behavior), define a node type using fkyaml::ordered_map as the second template parameter of fkyaml::basic_node.

    #include <fkYAML/node.hpp>
    
    // Define a node that preserves insertion order
    using ordered_node = fkyaml::basic_node<std::vector, fkyaml::ordered_map>;
  11. Install fkYAML via CMake

    develop

    To install fkYAML on your system, clone the repository and use CMake to configure and install it. You can optionally specify a custom installation path or choose to install the single-header version.

    Default Installation Paths:

    • UNIX: /usr/local
    • Windows: C:\Program Files\fkYAML

    Options:

    • -DCMAKE_INSTALL_PREFIX=<path-to-install>: Overrides the default installation path.
    • -DFK_YAML_USE_SINGLE_HEADER=ON: Installs the single-header version of fkYAML.
    $ cd /path/to/fkYAML
    $ cmake -B build -S . [-DCMAKE_INSTALL_PREFIX=<path-to-install>] [-DFK_YAML_USE_SINGLE_HEADER=ON]
    $ cmake --build build --target install