This commit is contained in:
Joao Paulo Magalhaes
2019-03-05 18:17:07 +00:00
parent b058c9b056
commit 53778c9546
2 changed files with 70 additions and 16 deletions

View File

@@ -30,7 +30,11 @@ ryml is written in C++11, and is known to compile with:
## Quick start ## Quick start
You can have your cake and eat it too: being fast doesn't need to mean being unpractical! You can have your cake and eat it too: being rapid doesn't mean being
unpractical! ryml was written with easy usage in mind, and comes with a two level
API for accessing and traversing the data tree: a low-level index-based API
and a higher level wrapping it via a ``NodeRef`` class. The examples in this
section are using the high-level ``NodeRef``.
Parsing from source: Parsing from source:
```c++ ```c++
@@ -59,18 +63,18 @@ parsing:
auto tree = ryml::parse("{foo: 1}"); auto tree = ryml::parse("{foo: 1}");
``` ```
`node.key()` and `node.val()` return an object of type `c4::csubstr` `node.key()` and `node.val()` return an object of type `c4::csubstr` (the
(*C*onstant *SUBSTR*ing) which is a read-only string-view, with some more name comes from constant substring) which is a read-only string view, with
methods that make it practical to use. There's also a writable `c4::substr` some more methods that make it practical to use. There's also a writable
string view, which in fact is used heavily by ryml to transform YAML blocks `c4::substr` string view, which in fact is used heavily by ryml to transform
and scalars during parsing. You can browse these classes here: YAML blocks and scalars during parsing. You can browse these classes
[https://github.com/biojppm/c4core/src/c4/substr.hpp](c4/substr.hpp). here: [c4/substr.hpp](https://github.com/biojppm/c4core/src/c4/substr.hpp).
To create a tree programatically: To create a tree programatically:
```c++ ```c++
ryml::Tree tree; ryml::Tree tree;
auto r = tree.rootref(); NodeRef r = tree.rootref();
r |= ryml::MAP; // this is needed to make the root a map r |= ryml::MAP; // this is needed to make the root a map
@@ -151,12 +155,59 @@ for(auto c : node.siblings())
} }
``` ```
For container-type nodes, the square-bracket operator can
be used either with integers (both for sequence and map nodes) or with
strings (only for map nodes):
```c++
ryml::Tree = ryml::parse("[a, b, {c: 0, d: 1}]");
ryml::NodeRef root = tree.rootref();
std::cout << root[0].val() << "\n"; // "a"
std::cout << root[1].val() << "\n"; // "b"
std::cout << root[2][ 0 ].val() << "\n"; // "0" // index-based
std::cout << root[2]["c"].val() << "\n"; // "0" // string-based
std::cout << root[2][ 1 ].val() << "\n"; // "1" // index-based
std::cout << root[2]["d"].val() << "\n"; // "1" // string-based
```
What about `NodeRef`? Before we look at it, let's take a moment to consider
when a non-existing key or index is requested via the square-bracket
operator. Unlike with `std::map`, this operator does *not* modify the tree.
Instead you get a seed `NodeRef`, and only if this seed-state ref is written
to will the tree be modified, by creating a node with the seed name or index.
To allow for this, `NodeRef` is a simple structure with a declaration like:
```c++
class NodeRef
{
// a pointer to the node tree
Tree * m_tree;
// either the (tree-scoped) index of an existing node or the (node-scoped) index of a seed state
size_t m_node_or_seed_id;
// the key name of a seed state
const char* m_seed_name;
public:
bool valid() { return m_node_id != npos && m_node_name == nullptr; }
// forward all calls to m_tree. For example:
csubstr val() const { assert(valid()); return m_tree->val(m_node_or_seed_id); }
void set_val(csubstr v) { if(!valid()) {/*create node in tree*/;} m_tree->set_val(m_node_or_seed_id, v); }
// etc
};
```
So using this high-level API is not going to cost a lot more than the less
practical low level API.
### STL interoperation ### STL interoperation
ryml does not require use of the STL. Use of STL is opt-in: you need to ryml does not require use of the STL. Use of STL is opt-in: you need to
`#include` the proper ryml header. Having done that, you can serialize them with a `#include` the proper ryml header. Having done that, you can serialize them
single step. For example: with a single step. For example:
```c++ ```c++
#include <ryml_std.hpp> #include <ryml_std.hpp>
@@ -211,10 +262,12 @@ It is important to overload these functions in the namespace where the type
you're serializing was defined, to you're serializing was defined, to
harness [C++'s ADL rules](http://en.cppreference.com/w/cpp/language/adl). harness [C++'s ADL rules](http://en.cppreference.com/w/cpp/language/adl).
### Low-level API ### Low-level API
... describe index-based API of the tree. ... describe index-based API of the tree.
### Custom allocation ### Custom allocation
... describe [custom allocation callbacks](src/c4/yml/common.hpp) ... describe [custom allocation callbacks](src/c4/yml/common.hpp)
@@ -223,6 +276,7 @@ harness [C++'s ADL rules](http://en.cppreference.com/w/cpp/language/adl).
... describe [the custom error handler callback](src/c4/yml/common.hpp) ... describe [the custom error handler callback](src/c4/yml/common.hpp)
## YAML standard conformance ## YAML standard conformance
ryml is under active development, but is close to feature complete. UTF8 has ryml is under active development, but is close to feature complete. UTF8 has
@@ -244,16 +298,16 @@ your bug reports or pull requests!
I am currently working on integrating (and fixing) the ~300 cases in the YAML I am currently working on integrating (and fixing) the ~300 cases in the YAML
test suite. test suite.
## Rapid? How rapid is it? ## Rapid? How rapid is it?
There are already some very impressive figures: compared There are already some very impressive figures: compared against
against [yaml-cpp](https://github.com/jbeder/yaml-cpp) in [yaml-cpp](https://github.com/jbeder/yaml-cpp) in a
a
[particular test case](https://github.com/biojppm/rapidyaml/issues/1#issuecomment-370300625), [particular test case](https://github.com/biojppm/rapidyaml/issues/1#issuecomment-370300625),
rapidyaml was ~5x faster (~20% CPU time) in Release builds and ~30x faster *rapidyaml was ~5x faster (~20% CPU time)* in Release builds and *~30x faster
(~3.5% CPU time) in Debug builds: (~3.5% CPU time) in Debug builds*:
[[[./.ci/first_comparison_yaml_cpp.png]]](https://github.com/biojppm/rapidyaml/issues/1#issuecomment-370300625) [![./img/first_comparison_yaml_cpp.png]](https://github.com/biojppm/rapidyaml/issues/1#issuecomment-370300625)
When I finish work on the test suite, I will get down to write some When I finish work on the test suite, I will get down to write some
comparison benchmarks. comparison benchmarks.

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB