{"id":17226979,"url":"https://github.com/dfeneyrou/styml","last_synced_at":"2026-04-29T07:35:20.193Z","repository":{"id":210787362,"uuid":"726570487","full_name":"dfeneyrou/styml","owner":"dfeneyrou","description":"C++ single-header STrictYaML parser and emitter ","archived":false,"fork":false,"pushed_at":"2025-10-24T08:10:56.000Z","size":143,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-24T10:12:08.541Z","etag":null,"topics":["configuration-file","ini","serialization","single-header","strictyaml","yaml"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dfeneyrou.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-02T18:45:37.000Z","updated_at":"2025-10-24T08:11:00.000Z","dependencies_parsed_at":"2024-12-03T14:43:40.064Z","dependency_job_id":"7f81cc5e-0e5c-48f5-805b-7ea754ccb0df","html_url":"https://github.com/dfeneyrou/styml","commit_stats":null,"previous_names":["dfeneyrou/styml"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dfeneyrou/styml","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfeneyrou%2Fstyml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfeneyrou%2Fstyml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfeneyrou%2Fstyml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfeneyrou%2Fstyml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dfeneyrou","download_url":"https://codeload.github.com/dfeneyrou/styml/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfeneyrou%2Fstyml/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32416146,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T06:29:02.080Z","status":"ssl_error","status_checked_at":"2026-04-29T06:29:00.631Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration-file","ini","serialization","single-header","strictyaml","yaml"],"created_at":"2024-10-15T04:17:43.029Z","updated_at":"2026-04-29T07:35:20.186Z","avatar_url":"https://github.com/dfeneyrou.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"![styml-logo](https://github.com/dfeneyrou/styml/blob/main/doc/images/styml-logo.png)\n\n[![Build and check](https://github.com/dfeneyrou/styml/actions/workflows/build.yml/badge.svg)](https://github.com/dfeneyrou/styml/actions/workflows/build.yml)\n\n## STYML : An efficient C++ single-header STrictYaML parser and emitter\n\nThe choice of data serialization formats seems large, but each of them comes at a cost:\n- YAML is readable, error-prone and bloated\n- JSON is simple, limited and verbose\n- XML is solid, hard to work with and hard to read for humans\n- TOML is minimal, noisy and scales poorly\n\n`styml` is an implementation of [StrictYAML](https://hitchdev.com/strictyaml) and aims at:\n- **simplicity**, by removing bloat from YAML\n- **readability**, inherited from YAML\n- **efficiency**, [fast](#parsing-speed) and [lean on memory](#memory-usage-factor)\n- **portability**, copying a single header is enough\n- **user friendliness**, with item order keeping, comment persistency and [O(1) map access](#document-access-speed)\n\n## A lean and practical subset of YAML\n\n`styml` is a subset of YAML with drastic cut-offs:\n - the heteroclite data types are removed: **all data are string** (not as crazy as it seems)\n - the superfluous **object representation** is removed\n - the complex and error-prone **anchors and references** are removed\n - the nested-secondary-syntax **JSON inline flow style** is removed\n - the **block mapping keys, or complex keys** are removed (keys are single line only)\n\n`styml` targets most use-cases from YAML (cross-language data sharing, log files, interprocess messaging, object persistence, configuration files, ...) without entering the [feature-creep zone](https://en.wikipedia.org/wiki/Feature_creep).  \nIndeed, at the price of not fitting some projects that genuinely require these advanced/complex features.\n\n## Quick start\n\n1) Copy `styml.h` into your project. No external dependencies.\n2) Add a few lines of code, as in the example below\n``` C++\n    #include \"styml.h\"\n    ...\n\n    // Parse the input text string\n    styml::Document root;\n    try {\n        root = styml::parse(inputStringText);\n    } catch (styml::ParseException\u0026 e) {\n        ...\n    }\n\n    // Read items\n    std::string ciRunCmds = root[\"build\"][\"steps\"][0][\"run\"].as\u003cstd::string\u003e();\n    float fontSize = root[\"build\"][\"font size\"].as\u003cfloat\u003e(16.); // With default\n\n    // Write items\n    root[\"build\"][\"font size\"] = fontSize + 1.;\n\n    // Emit (strings are easily saved on disk)\n    std::string pythonString = root.asPyStruct(); // Emit as python structure\n    std::string yamlString = root.asYaml(); // Emit as YAML, keeping comments and item order\n```\n\nAs measured in the [performance section](#performance), `styml` is fast enough to be directly used as a live database for configuration.\n\n\n## API\n\nThe API is quite straightforward, especially if you are familiar with `yaml-cpp`.\n\nThe two main sections are:\n \n\u003cdetails\u003e\n\u003csummary\u003e [Click to open] A `parse` function to create a `Document` from a string \u003c/summary\u003e\n\n### Document and parsing function\n\nA `Document` is simply a (root) `Node` with 2 additional features:\n - it owns the YAML tree\n   - its destruction releases the document. All `Node` objects related to it are invalidated and shall no more be used.\n - it owns the emission API\n   - `std::string asPyStruct(bool withIndent = false) const` emits a Python evaluable string, compact (default) or with indent\n   - `std::string asYaml() const` emits a YAML string\n\nA `Document` can be created from scratch.\n```C++\n// preference:\n//   font size: 4\n//   font name: helvetica\n//   names:\n//     - toto\n//     - 14\nstyml::Document doc;\ndoc = styml::NodeType::MAP; // Choice is between MAP and SEQUENCE. This choice must be done.\n\ndoc[\"preferences\"]              = styml::NodeType::MAP; // This node is also a MAP\ndoc[\"preferences\"][\"font size\"] = 4;\ndoc[\"preferences\"][\"font name\"] = \"Helvetica\";\n\ndoc[\"preferences\"][\"names\"] = styml::NodeType::SEQUENCE; // This node is a SEQUENCE\ndoc[\"preferences\"][\"names\"].push_back(\"toto\");\ndoc[\"preferences\"][\"names\"].push_back(14); // Just for example, as this number is turned into a string \n```\n\nIt can also be created from a YAML string in memory with one of the following function:\n```C++\n// Canonical form\nstyml::Document parse(const std::string\u0026 text);\n\n// Variant with const char* input. It does not need to be zero terminated\nstyml::Document parse(const char* text, uint32_t textSize);\n\n// Variant with const char* input. It must be zero terminated\nstyml::Document parse(const char* text);\n```\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003e [Click to open] A `Node` class representing a typed item in the YAML tree \u003c/summary\u003e\n\n### Node\n\nThe main object in `styml` is `Node`, which represent a typed item in the YAML tree.  \nIt can have 4 different types:\n\n| Node type | Description | Comments | Example |\n|:----------|:------------|:---------|:--------|\n|`NodeType::VALUE` | In StrictYAML, a value is always a string | Converted into a compatible format with `.as\u003cType\u003e()` or `.as\u003cType\u003e(default value)` | `25` in `age: 25` is a convertible string|\n|`NodeType::SEQUENCE` | A sequence container is an ordered list of children of any type, except `NodeType::KEY` | Children are accessed by their index number | `- a` is a sequence of size 1 containing a value string |\n| `NodeType::MAP` | A map container is an unordered list of children exclusively of type `NodeType::KEY` | Children are accessed by their string name | `age: 25` is a map of size 1 containing a child key named `age` |\n| `NodeType::COMMENT` | Represents a comment item | | `# This is a comment` | \n\n\nThe `Node` API is restricted depending on its type, as shown in the table below (\"X\" means accessible):\n\n| Method                                      | Value | Sequence | Map | Key           | Comment |\n|:--------------------------------------------|:-----:|:--------:|:---:|:-------------:|:-------:|\n| `NodeType type()`                           | X     | X        | X   | X             | X       |\n| `bool isValue()`                            | X     | X        | X   | X             | X       |\n| `bool isKey()`                              | X     | X        | X   | X             | X       |\n| `bool isSequence()`                         | X     | X        | X   | X             | X       |\n| `bool isMap()`                              | X     | X        | X   | X             | X       |\n| `bool isComment()`                          | X     | X        | X   | X             | X       |\n| | | | | | |\n| `Node\u0026 operator=(const T\u0026)`                 | X     | X        | X   | X (via value) |         |\n| `Node\u0026 operator=(newKind)`                  | X     | X        | X   | X (via value) |         |\n| `std::string keyName()`                     |       |          |     | X             |         |\n| `Node value()`                              |       |          |     | X             |         |\n| `as\u003cT\u003e()`                                   | X     |          |     | X (via value) |         |\n| `as\u003cT\u003e(const T\u0026 deflt)`                     | X     |          |     | X (via value) |         |\n| | | | | | |\n| `iterator begin()`                          |       | X        | X   |               |         |\n| `iterator end()`                            |       | X        | X   |               |         |\n| `size_t size()`                             |       | X        | X   |               |         |\n| | | | | | |\n| `Node operator[](uint32_t)`                 |       | X        |     |               |         |\n| `void push_back(const T\u0026)`                  |       | X        |     |               |         |\n| `void push_back(NodeType)`                  |       | X        |     |               |         |\n| `void insert(uint32_t, const T\u0026)`           |       | X        |     |               |         |\n| `void insert(uint32_t, NodeType)`           |       | X        |     |               |         |\n| `void remove(uint32_t)`                     |       | X        |     |               |         |\n| `void pop_back()`                           |       | X        |     |               |         |\n| | | | | | |\n| `bool hasKey(const std::string\u0026)`           |       |          | X   |               |         |\n| `Node operator[](const std::string\u0026)`       |       |          | X   |               |         |\n| `void insert(const std::string\u0026, const T\u0026)` |       |          | X   |               |         |\n| `void insert(const std::string\u0026, NodeType)` |       |          | X   |               |         |\n| `bool remove(const std::string\u0026)`           |       |          | X   |               |         |\n\n\u003c/details\u003e\n\n\nComplementary information below:\n\n\u003cdetails\u003e\n\u003csummary\u003e [Click to open] About exceptions \u003c/summary\u003e\n\n### Exceptions\n\nAfter careful consideration, `styml` error handling is based on C++ exceptions rather than carrying an error context in each API:\n - it enables bloat-free tree manipulation API like the `operator[]` which is a natural access for containers\n - it allows a global handling of error for a whole section of YAML tree manipulation\n\nSpecial care was taken to the error messages and exceptions are kept simple.  \nThey just contain a message (queried with standard `what()`) and can be of 3 kinds:\n - `ParseException` raised only during parsing.\n - `AccessException` raised when manipulating the tree\n - `ConvertException` not seen by user but shall be thrown when implementing a custom type converter.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e [Click to open] Examples \u003c/summary\u003e\n\n### Examples\n\n#### Parsing a YAML string and emitting it in Python\n\n```C++\nconst char* inputText = R\"END(\nfoo: 1\nbar: John Doe\n)END\";\n\n// Parse\nstyml::Document root;\ntry {\n  root = styml::parse(inputText);\n} catch (styml::ParseException\u0026 e) {\n    printf(\"Parsing error: %s\\n\", e.what());\n    exit(1);\n}\n\n// Emit in Python with indentation (bigger but more readable for human)\nstd::string output = root.asPyStruct(true);\nprintf(\"%s\\n\", output.c_str());\n```\n\n#### Reading and writing fields\n\n```C++\nconst char* document = R\"END(\nname: build machine\nsteps:\n)END\";\n\nDocument root = parse(document);\nassert(root[\"name\"].as\u003cstd::string\u003e()==std::string(\"build machine\"));\nassert(root[\"steps\"].as\u003cstd::string\u003e()==std::string(\"\"));\n\nroot[\"version\"] = \"1.0.0\";\nroot[\"steps\"] = styml::SEQUENCE; // Override the empty string with a sequence\nroot[\"steps\"].push_back(\"first value is string\");\nroot[\"steps\"].push_back(3.14159); // Reminder: stored as a string\n\nprintf(\"YAML:\\n%s\\n\", root.asYaml().c_str());\n/* Output is:\nYAML:\nname: build machine\nsteps:\n  - first value is string\n  - 3.141590\nversion: 1.0.0\n*/\n```\n\n#### Building a map from scratch and accessing it\n\n```C++\nconstexpr int MaxMapSize = 1000000;\nDocument root;\n\n// Create the lookup \"\u003cnumber\u003e\" = number (stored as a string)\nroot = NodeType::MAP;\nfor (int i = 0; i \u003c MaxMapSize; ++i) { root[std::to_string(i)] = i; }\n\n// Remove 1 each 3\nfor (int i = 0; i \u003c MaxMapSize; i += 3) { root.remove(std::to_string(i)); }\n\n// Check correctness\nfor (int i = 0; i \u003c MaxMapSize; ++i) {\n   if ((i % 3) == 0) {\n        assert(!root.hasKey(keys[i]));\n    } else {\n        Node n = root[std::to_string(i)];\n        assert(n.isValue());\n        assert(n.as\u003cstd::string\u003e() == std::to_string(i));\n    }\n}\n```\n\n#### Building a sequence from scratch and accessing it\n\n```C++\nconstexpr int MaxSequenceSize = 1000000;\nDocument root;\n\n// Create the array of doubles (stored as a string)\nroot = NodeType::SEQUENCE;\nfor (int i = 0; i \u003c MaxSequenceSize; ++i) { root.push_back(2 * i); }\n\n// Check correctness\nfor (int i = 0; i \u003c MaxSequenceSize; ++i) {\n    assert(root[i].as\u003cint\u003e()== 2* i);\n}\n```\n\n\u003c/details\u003e\n\n## Performance\n\nTo evaluate performance with references, `styml` is compared to the following C++ YAML libraries:\n - [`yaml-cpp`](https://github.com/jbeder/yaml-cpp) (popular)\n - [`rapidyaml`](https://github.com/biojppm/rapidyaml) (high performance)\n\nTo be fair, please note that these libraries are full-featured YAML and have to deal with more complexity that `styml` has to.  \nOn the other side, trading complexity for benefits is exactly the point...\n\nMeasures are all done on the same laptop (i7-11800H @2.30GHz on Linux).\n\n**TL;DR: Results show that `styml` leverages the gained simplification: it is much faster and memory efficient than both libraries above, with multiple order of magnitude on the access timings.**\n\nSome key details about the implementation leading to these results:\n - Use of arena allocator to store and work efficiently with strings \n - Use of high performance hashtable for O(1) access time for maps\n - Use of efficient storage and document tree representation to achieve low memory footprint\n\nThe code used to evaluate these libraries can be found [here](https://github.com/dfeneyrou/styml/tree/main/doc/vendors).\n\nThe reference YAML files are taken from [`rapidyaml`](https://github.com/biojppm/rapidyaml/tree/master/bm/cases) and are compatible with StrictYAML:\n- [style_maps_blck_outer1000_inner1000.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/style_maps_blck_outer1000_inner1000.yml), aka \"Map\", map intensive (10.8 MB)\n- [style_seqs_blck_outer1000_inner1000.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/style_seqs_blck_outer1000_inner1000.yml), aka \"Seq\", sequence intensive (7.9 MB)\n\n### Parsing speed\n\n The parsing speed is the size of the input file divided by the time to parse it into a usable structure in memory.\n \n | Filename | yaml-cpp   | rapidyaml (in place) | styml            | Speed factor   |\n |----------|:----------:|:--------------------:|:----------------:|:--------------:|\n | \"Map\"    | 4.958 MB/s | 55.688 MB/s          | **70.644 MB/s**  | 14.2x and 1.3x |\n | \"Seq\"    | 5.808 MB/s | 47.214 MB/s          | **138.082 MB/s** | 23.8x and 2.9x |\n\n\u003e [!NOTE]\n\u003e `styml` parses between 30% and 200% faster than `rapidyaml`, and at least 14 times faster than `yaml-cpp`.  \n\u003e **Benefit from StrictYAML simplification:** less syntax to handle means more speed.\n\n### Memory usage factor\n\nThe memory factor is the quantity of memory used after parsing divided by the input file size:\n\n | Filename                 | yaml-cpp         | rapidyaml (in place) | styml              | Memory gain    |\n |--------------------------|:----------------:|:--------------------:|:------------------:|:--------------:|\n | \"Map\" (filesize 10.8 MB) | 87.7x (945.2 MB) | 14.9x (160.6 MB)     | **6.8x** (73.3 MB) | 12.9x and 2.2x |\n | \"Seq\" (filesize 7.9 MB)  | 64.0x (505.1 MB) | 20.4x (160.6 MB)     | **3.6x** (28.2 MB) | 17.9x and 5.7x |\n\n\u003e [!NOTE]\n\u003e `styml` uses less than half the memory consumed by `rapidyaml` and 60x less memory than `yaml-cpp`, while also indexing map access.  \n\u003e **Benefit from StrictYAML simplification:** less object types to encode means more optimized memory layout.\n\n### YAML Emission speed\n\nThe emission speed is the size of the input file divided by the time to emit it back in YAML (after parsing, excluded from the measure):\n\n | Filename | yaml-cpp   | rapidyaml    | styml            | Speed factor   |\n |----------|:----------:|:------------:|:----------------:|:--------------:|\n | \"Map\"    | 7.766 MB/s | 266.436 MB/s | **326.281 MB/s** | 42.0x and 1.2x |\n | \"Seq\"    | 9.871 MB/s | **353.479 MB/s** | 323.400 MB/s | 32.8x and 0.9x |\n\n\u003e [!NOTE]\n\u003e `styml` and `rapidyaml` are emitting YAML roughly at the same speed, for a mix of maps and sequences.\n\u003e `styml` is also able to emit python structures at the speed of 416 MB/s and 593 MB/s respectively.\n\n### Document access speed\n\nBuilding (=writing) a document programmatically from scratch through the API, in millions of items per second:\n| Filename            | yaml-cpp                | rapidyaml               | styml           | Speed factor  |\n|---------------------|:-----------------------:|:-----------------------:|:---------------:|:-------------:|\n| Map of 10000        | 0.014 Mi/s              | 0.053 Mi/s              | **9.091 Mi/s**  | 649x and 168x |\n| Sequence of 10000   | 4.517 Mi/s              | 0.075 Mi/s              | **42.194 Mi/s** | 9x and 562x   |\n| Map of 1000000      | _(quadratic, too slow)_ | _(quadratic, too slow)_ | **7.875 Mi/s**  | N/A           |\n| Sequence of 1000000 | 3.700 Mi/s              | _(quadratic, too slow)_ | **39.569 Mi/s** | 10x and N/A   |\n\n\u003e [!NOTE]\n\u003e Only `styml` has a O(1) access time per map field, others have a O(N) leading to quadratic time for a full build.  \n\u003e `rapidyaml` does not even take benefit from the random access property of sequences.\n\n\u003cbr/\u003e\n\nReading fields of a document programmatically through the API, in millions of items per second:\n| Filename            | yaml-cpp      | rapidyaml     | styml              | Speed factor     |\n|---------------------|:-------------:|:-------------:|:------------------:|:----------------:|\n| Map of 10000        | 0.014 Mi/s    | 0.053 Mi/s    | **42.553 Mi/s**    | 3000x and 800x   |\n| Sequence of 10000   | 37.037 Mi/s   | 0.076 Mi/s    | **~1000.000 Mi/s** | ~30x and ~10000x |\n| Map of 1000000      | _(quadratic)_ | _(quadratic)_ | **23.317 Mi/s**    | N/A              |\n| Sequence of 1000000 | 25.757 Mi/s   | _(quadratic)_ | **745.712 Mi/s**   | 29x and N/A      |\n\n\u003e [!NOTE]\n\u003e `rapidyaml` scales poorly with large structure access and it handles sequences like maps, in a quadratic way.  \n\u003e `yaml-cpp` has a genuine but rather slow random access for sequence when reading an indexed array.\n\n\n## Misc\n\n### Extension with custom type\n\n\u003cdetails\u003e\n\u003csummary\u003e [Click to open] Full description how to add a custom type \u003c/summary\u003e\n\nConverters from/to strings are built-in for usual types:\n``` C++\nint valueInt                  = valueNode.as\u003cint\u003e();\nint valueUInt32               = valueNode.as\u003cuint32_t\u003e();\nint valueDouble               = valueNode.as\u003cdouble\u003e();\nstd::string valueString       = valueNode.as\u003cstd::string\u003e();\nconst char* valueConstCharPtr = valueNode.as\u003cconst char*\u003e();\n...\n```\n\nDefining conversions for your own types is done by specializing the `styml::convert\u003c\u003e` class.  \n\nThe example below explains the different steps:\n - Let's consider the custom point structure:\n``` C++\n// Custom structure\nstruct MyPoint {\n    float x;\n    float y;\n    int   value;\n};\n```\n- An implementation of the converter specializing the `styml::convert\u003c\u003e` class is:\n``` C++\nnamespace styml\n{\ntemplate\u003c\u003e\nstruct convert\u003cMyPoint\u003e {\n    // From custom type to std::string. The format (here with brackets) does not matter as long\n    // as it stays on one line and the encode and decode methods are matching.\n    static std::string encode(const MyPoint\u0026 point)\n    {\n        char workBuf[256];\n        if (snprintf(workBuf, sizeof(workBuf), \"[ %f, %f, %d ]\", point.x, point.y, point.value) == sizeof(workBuf)) {\n            throwMessage\u003cConvertException\u003e(\"Too small internal buffer (%zu) for encoding\", sizeof(workBuf));\n        }\n        return workBuf;\n    }\n\n    // From C string to custom type\n    static void decode(const char* strValue, MyPoint\u0026 point)\n    {\n        if (sscanf(strValue, \"[ %f, %f, %d ]\", \u0026point.x, \u0026point.y, \u0026point.value) != 3) {\n            throwMessage\u003cConvertException\u003e(\"Cannot convert the following string into a MyPoint structure: '%s'\", strValue);\n        }\n    }\n};\n}  // namespace styml\n```\n- And its usage is identical to built-in types:\n``` C++\nMyPoint point{3.14f, 2.78f, 42};\n\n// The structure ''MyPoint' is turned into a string via a call to convert\u003cMyPoint\u003e::encode\nroot[\"custom\"] = point;\n\n// The string is turned into a 'MyPoint' structure via a call to convert\u003cMyPoint\u003e::decode\nMyPoint pointRead = root[\"custom struct\"].as\u003cMyPoint\u003e();\n\nassert(memcmp(\u0026pointRead, \u0026point, sizeof(MyPoint)) == 0);\n```\n\n\u003e __IMPORTANT:__\n\u003e  - the conversion class shall be placed in the `styml` namespace\n\u003e  - it is up to the conversion class to throw the `ConvertException` in case of syntax errors\n\u003e  - design note: the usage of std::string and exceptions are used for convenience, not performance\n\n\u003c/details\u003e\n\n\n### Support\n\n`styml` requires C++17 or above.\n\nSupported OS:\n - Linux\n - Windows\n\nNote: performance on Windows are lower than on Linux.\n\n### Limitations\n\n- Missing API to modify comments\n- Partial unicode escaping\n\nAlso this project is young, feedback is welcome!\n\n### License\n\n`styml` source code is available under the [MIT license](https://github.com/dfeneyrou/styml/blob/master/LICENSE)\n\nAssociated components:\n - Hash function: [`Wyhash`](https://github.com/wangyi-fudan/wyhash)\n   - Selected for its [good non-cryptographic properties, speed and small code size](https://github.com/rurban/smhasher#summary)\n   - Released in the [public domain](http://unlicense.org/) \n- Test framework: [`doctest`](https://github.com/doctest/doctest)\n   - Released under the [MIT license](https://github.com/doctest/doctest/blob/master/LICENSE.txt)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfeneyrou%2Fstyml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdfeneyrou%2Fstyml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfeneyrou%2Fstyml/lists"}