rapidyaml  0.16.0
parseandemitYAML,anddoitfast

Functions

void sample_iterate_tree ()
 visit individual nodes and iterate through trees More...
 
void sample_location_tracking ()
 track node YAML source locations in the parsed tree More...
 
void sample_create_tree ()
 programatically create trees More...
 
void sample_create_tree_style ()
 set node styles while creating trees More...
 
void sample_tree_arena ()
 interact with the tree's serialization arena More...
 

Detailed Description

Function Documentation

void sample_iterate_tree ( )

visit individual nodes and iterate through trees

shows how to programatically iterate through trees

See also
Tree utilities
Node classes

Definition at line 2398 of file quickstart.cpp.

Referenced by main().

2399 {
2400  const ryml::Tree tree = ryml::parse_in_arena(
2401  "doe: a deer, a female deer" "\n"
2402  "ray: a drop of golden sun" "\n"
2403  "pi: 3.14159" "\n"
2404  "xmas: true" "\n"
2405  "french-hens: 3" "\n"
2406  "calling-birds:" "\n"
2407  " - huey" "\n"
2408  " - dewey" "\n"
2409  " - louie" "\n"
2410  " - fred" "\n"
2411  "xmas-fifth-day:" "\n"
2412  " calling-birds: four" "\n"
2413  " french-hens: 3" "\n"
2414  " golden-rings: 5" "\n"
2415  " partridges:" "\n"
2416  " count: 1" "\n"
2417  " location: a pear tree" "\n"
2418  " turtle-doves: two" "\n"
2419  "cars: GTO" "\n"
2420  "");
2421  ryml::ConstNodeRef root = tree.crootref();
2422 
2423  // iterate children
2424  {
2425  std::vector<ryml::csubstr> keys, vals; // to store all the root-level keys, vals
2426  for(ryml::ConstNodeRef n : root.children())
2427  {
2428  keys.emplace_back(n.key());
2429  vals.emplace_back(n.has_val() ? n.val() : ryml::csubstr{});
2430  }
2431  CHECK(keys.size() >= 6);
2432  CHECK(vals.size() >= 6);
2433  if(keys.size() >= 6 && vals.size() >= 6)
2434  {
2435  CHECK(keys[0] == "doe");
2436  CHECK(vals[0] == "a deer, a female deer");
2437  CHECK(keys[1] == "ray");
2438  CHECK(vals[1] == "a drop of golden sun");
2439  CHECK(keys[2] == "pi");
2440  CHECK(vals[2] == "3.14159");
2441  CHECK(keys[3] == "xmas");
2442  CHECK(vals[3] == "true");
2443  CHECK(root[5].has_key());
2444  CHECK(root[5].is_seq());
2445  CHECK(root[5].key() == "calling-birds");
2446  CHECK(!root[5].has_val()); // it is a map, so not a val
2447  //CHECK(root[5].val() == ""); // ERROR! node does not have a val.
2448  CHECK(keys[5] == "calling-birds");
2449  CHECK(vals[5] == "");
2450  }
2451  }
2452 
2453  // iterate siblings
2454  {
2455  size_t count = 0;
2456  ryml::csubstr calling_birds[] = {"huey", "dewey", "louie", "fred"};
2457  for(ryml::ConstNodeRef n : root["calling-birds"][2].siblings())
2458  CHECK(n.val() == calling_birds[count++]);
2459  CHECK(count == 4u);
2460  }
2461 }
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *tree, id_type node_id)
(1) parse YAML into an existing tree node. The filename will be used in any error messages arising du...
Definition: parse.cpp:209
ConstNodeRef crootref() const
Get the root as a ConstNodeRef . Note that Tree implicitly converts to ConstNodeRef.
Definition: tree.cpp:65
#define CHECK(predicate)
a testing assertion, used only in this quickstart
Definition: quickstart.cpp:310
Holds a pointer to an existing tree, and a node id.
Definition: node.hpp:736
const_children_view children() const RYML_NOEXCEPT
get an iterable view over children
Definition: node.hpp:987
void sample_location_tracking ( )

track node YAML source locations in the parsed tree

demonstrates how to obtain the (zero-based) location of a node from a recently parsed tree

See also
RYML_LOCATIONS_SMALL_THRESHOLD

Definition at line 2471 of file quickstart.cpp.

Referenced by main().

2472 {
2473  // NOTE: locations are zero-based. If you intend to show the
2474  // location to a human user, you may want to pre-increment the line
2475  // and column by 1.
2476  ryml::csubstr yaml = ""
2477  "{" "\n"
2478  "aa: contents," "\n"
2479  "foo: [one, [two, three]]" "\n"
2480  "}" "\n"
2481  "";
2482  // A parser is needed to track locations, and it has to be
2483  // explicitly set to do it. Location tracking is disabled by
2484  // default.
2485  ryml::ParserOptions opts = {};
2486  opts.locations(true); // enable locations, default is false
2487  ryml::EventHandlerTree evt_handler = {};
2488  ryml::Parser parser(&evt_handler, opts);
2489  CHECK(parser.options().locations());
2490  // When locations are enabled, the first task while parsing will
2491  // consist of building and caching (in the parser) a
2492  // source-to-node lookup structure to accelerate location lookups.
2493  //
2494  // The cost of building the location accelerator is linear in the
2495  // size of the source buffer. This increased cost is the reason
2496  // for the opt-in requirement. When locations are disabled there
2497  // is no cost.
2498  //
2499  // Building the location accelerator may trigger an allocation,
2500  // but this can and should be avoided by reserving prior to
2501  // parsing:
2502  parser.reserve_locations(50u); // reserve for 50 lines of YAML code
2503  // Now the structure will be built during parsing:
2504  ryml::Tree tree = parse_in_arena(&parser, "source.yml", yaml);
2505  // After this, we are ready to query the location from the parser:
2506  ryml::Location loc = tree.rootref().location(parser);
2507  // As for the complexity of the query: for large buffers it is
2508  // O(log(numlines)). For short source buffers
2509  // (RYML_LOCATIONS_SMALL_THRESHOLD lines and less), it is
2510  // O(numlines), as a plain linear search is faster in this case.
2511  CHECK(parser.location_contents(loc).begins_with("{"));
2512  CHECK(loc.offset == 0u);
2513  CHECK(loc.line == 0u);
2514  CHECK(loc.col == 0u);
2515  // on the next call, we only pay O(log(numlines)) because the
2516  // rebuild is already available:
2517  loc = tree["aa"].location(parser);
2518  CHECK(parser.location_contents(loc).begins_with("aa"));
2519  CHECK(loc.offset == 2u);
2520  CHECK(loc.line == 1u);
2521  CHECK(loc.col == 0u);
2522  // KEYSEQ in flow style: points at the key
2523  loc = tree["foo"].location(parser);
2524  CHECK(parser.location_contents(loc).begins_with("foo"));
2525  CHECK(loc.offset == 16u);
2526  CHECK(loc.line == 2u);
2527  CHECK(loc.col == 0u);
2528  loc = tree["foo"][0].location(parser);
2529  CHECK(parser.location_contents(loc).begins_with("one"));
2530  CHECK(loc.line == 2u);
2531  CHECK(loc.col == 6u);
2532  // SEQ in flow style: location points at the opening '[' (there's no key)
2533  loc = tree["foo"][1].location(parser);
2534  CHECK(parser.location_contents(loc).begins_with("["));
2535  CHECK(loc.line == 2u);
2536  CHECK(loc.col == 11u);
2537  loc = tree["foo"][1][0].location(parser);
2538  CHECK(parser.location_contents(loc).begins_with("two"));
2539  CHECK(loc.line == 2u);
2540  CHECK(loc.col == 12u);
2541  loc = tree["foo"][1][1].location(parser);
2542  CHECK(parser.location_contents(loc).begins_with("three"));
2543  CHECK(loc.line == 2u);
2544  CHECK(loc.col == 17u);
2545  // NOTE. The parser locations always point at the latest buffer to
2546  // be parsed with the parser object, so they must be queried using
2547  // the corresponding latest tree to be parsed. This means that if
2548  // the parser is reused, earlier trees will loose the possibility
2549  // of querying for location. It is undefined behavior to query the
2550  // parser for the location of a node from an earlier tree:
2551  ryml::Tree docval = parse_in_arena(&parser, "docval.yaml", "this is a docval");
2552  // From now on, none of the locations from the previous tree can
2553  // be queried:
2554  //loc = tree.rootref().location(parser); // ERROR, undefined behavior
2555  loc = docval.rootref().location(parser); // OK. this is the latest tree from this parser
2556  CHECK(parser.location_contents(loc).begins_with("this is a docval"));
2557  CHECK(loc.line == 0u);
2558  CHECK(loc.col == 0u);
2559 
2560  // NOTES ABOUT CONTAINER LOCATIONS
2561  ryml::Tree tree2 = parse_in_arena(&parser, "containers.yaml",
2562  "" "\n"
2563  "a new: buffer" "\n"
2564  "to: be parsed" "\n"
2565  "map with key:" "\n"
2566  " first: value" "\n"
2567  " second: value" "\n"
2568  "seq with key:" "\n"
2569  " - first value" "\n"
2570  " - second value" "\n"
2571  " -" "\n"
2572  " - nested first value" "\n"
2573  " - nested second value" "\n"
2574  " -" "\n"
2575  " nested first: value" "\n"
2576  " nested second: value" "\n"
2577  "");
2578  // (Likewise, the docval tree can no longer be used to query.)
2579  //
2580  // For key-less block-style maps, the location of the container
2581  // points at the first child's key. For example, in this case
2582  // the root does not have a key, so its location is taken
2583  // to be at the first child:
2584  loc = tree2.rootref().location(parser);
2585  CHECK(parser.location_contents(loc).begins_with("a new"));
2586  CHECK(loc.offset == 1u);
2587  CHECK(loc.line == 1u);
2588  CHECK(loc.col == 0u);
2589  // note the first child points exactly at the same place:
2590  loc = tree2["a new"].location(parser);
2591  CHECK(parser.location_contents(loc).begins_with("a new"));
2592  CHECK(loc.offset == 1u);
2593  CHECK(loc.line == 1u);
2594  CHECK(loc.col == 0u);
2595  loc = tree2["to"].location(parser);
2596  CHECK(parser.location_contents(loc).begins_with("to"));
2597  CHECK(loc.line == 2u);
2598  CHECK(loc.col == 0u);
2599  // but of course, if the block-style map is a KEYMAP, then the
2600  // location is the map's key, and not the first child's key:
2601  loc = tree2["map with key"].location(parser);
2602  CHECK(parser.location_contents(loc).begins_with("map with key"));
2603  CHECK(loc.line == 3u);
2604  CHECK(loc.col == 0u);
2605  loc = tree2["map with key"]["first"].location(parser);
2606  CHECK(parser.location_contents(loc).begins_with("first"));
2607  CHECK(loc.line == 4u);
2608  CHECK(loc.col == 2u);
2609  loc = tree2["map with key"]["second"].location(parser);
2610  CHECK(parser.location_contents(loc).begins_with("second"));
2611  CHECK(loc.line == 5u);
2612  CHECK(loc.col == 2u);
2613  // same thing for KEYSEQ:
2614  loc = tree2["seq with key"].location(parser);
2615  CHECK(parser.location_contents(loc).begins_with("seq with key"));
2616  CHECK(loc.line == 6u);
2617  CHECK(loc.col == 0u);
2618  loc = tree2["seq with key"][0].location(parser);
2619  CHECK(parser.location_contents(loc).begins_with("first value"));
2620  CHECK(loc.line == 7u);
2621  CHECK(loc.col == 4u);
2622  loc = tree2["seq with key"][1].location(parser);
2623  CHECK(parser.location_contents(loc).begins_with("second value"));
2624  CHECK(loc.line == 8u);
2625  CHECK(loc.col == 4u);
2626  // SEQ nested in SEQ: container location points at the first child's "- " dash
2627  loc = tree2["seq with key"][2].location(parser);
2628  CHECK(parser.location_contents(loc).begins_with("- nested first value"));
2629  CHECK(loc.line == 10u);
2630  CHECK(loc.col == 4u);
2631  loc = tree2["seq with key"][2][0].location(parser);
2632  CHECK(parser.location_contents(loc).begins_with("nested first value"));
2633  CHECK(loc.line == 10u);
2634  CHECK(loc.col == 6u);
2635  // MAP nested in SEQ: same as above: point to key
2636  loc = tree2["seq with key"][3].location(parser);
2637  CHECK(parser.location_contents(loc).begins_with("nested first: "));
2638  CHECK(loc.line == 13u);
2639  CHECK(loc.col == 4u);
2640  loc = tree2["seq with key"][3][0].location(parser);
2641  CHECK(parser.location_contents(loc).begins_with("nested first: "));
2642  CHECK(loc.line == 13u);
2643  CHECK(loc.col == 4u);
2644 }
size_t offset
number of bytes from the beginning of the source buffer
Definition: common.hpp:230
Location location(Parser const &parser) const
Definition: node.hpp:318
size_t col
column
Definition: common.hpp:232
The event handler to create a ryml Tree.
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *tree, id_type node_id)
(1) parse YAML into an existing tree node. The filename will be used in any error messages arising du...
Definition: parse.cpp:209
Options to give to the ParseEngine to control its behavior.
Parser parser
Definition: parse.cpp:117
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition: common.hpp:228
#define CHECK(predicate)
a testing assertion, used only in this quickstart
Definition: quickstart.cpp:310
ParserOptions & locations(bool enabled) noexcept
enable/disable source location tracking.
NodeRef rootref()
Get the root as a NodeRef . Note that a non-const Tree implicitly converts to NodeRef.
Definition: tree.cpp:56
This is the main driver of parsing logic: it scans the YAML or JSON source for tokens, and emits the appropriate sequence of parsing events to its event handler.
Definition: fwd.hpp:17
Location location(Parser const &p, id_type node) const
Get the location of a node from the parse used to parse this tree.
Definition: tree.cpp:1913
size_t line
line
Definition: common.hpp:231
void sample_create_tree ( )

programatically create trees

shows how to programatically create trees

See also
Tree utilities
Node classes
sample_create_tree_style()

Definition at line 2654 of file quickstart.cpp.

Referenced by main().

2655 {
2656  ryml::NodeRef doe;
2657  CHECK(doe.invalid()); // it's pointing at nowhere
2658 
2659  ryml::Tree tree;
2660  ryml::NodeRef root = tree.rootref();
2661  root.set_map(); // mark root as a map
2662  doe = root["doe"];
2663  CHECK(!doe.invalid()); // it's now pointing at the tree
2664  CHECK(doe.is_seed()); // but the tree has nothing there, so this is only a seed
2665 
2666  // set the value of the node
2667  const char a_deer[] = "a deer, a female deer";
2668  doe.set_val(a_deer);
2669  // now the node really exists in the tree, and this ref is no
2670  // longer a seed:
2671  CHECK(!doe.is_seed());
2672  // WATCHOUT for lifetimes:
2673  CHECK(doe.val().str == a_deer); // it is pointing at the initial string
2674  // If you need to avoid lifetime dependency, serialize the data:
2675  {
2676  std::string a_drop = "a drop of golden sun";
2677  // this will copy the string to the tree's arena:
2678  // (see the serialization samples below)
2679  root["ray"].set_serialized(a_drop);
2680  // and now you can modify the original string without changing
2681  // the tree:
2682  a_drop[0] = 'Z';
2683  a_drop[1] = 'Z';
2684  }
2685  CHECK(root["ray"].val() == "a drop of golden sun");
2686 
2687  // etc.
2688  root["pi"].set_serialized(ryml::fmt::real(3.141592654, 5));
2689  root["xmas"].set_serialized(ryml::fmt::boolalpha(true));
2690  root["french-hens"].set_serialized(3);
2691  ryml::NodeRef calling_birds = root["calling-birds"];
2692  calling_birds.set_seq();
2693  calling_birds.append_child().set_val("huey");
2694  calling_birds.append_child().set_val("dewey");
2695  calling_birds.append_child().set_val("louie");
2696  calling_birds.append_child().set_val("fred");
2697  ryml::NodeRef xmas5 = root["xmas-fifth-day"];
2698  xmas5.set_map();
2699  xmas5["calling-birds"].set_val("four");
2700  xmas5["french-hens"].set_serialized(3);
2701  xmas5["golden-rings"].set_serialized(5);
2702  xmas5["partridges"].set_map();
2703  xmas5["partridges"]["count"].set_serialized(1);
2704  xmas5["partridges"]["location"].set_val("a pear tree");
2705  xmas5["turtle-doves"].set_val("two");
2706  root["cars"].set_val("GTO");
2707 
2708  CHECK(ryml::emitrs_yaml<std::string>(tree) == ""
2709  "doe: a deer, a female deer" "\n"
2710  "ray: a drop of golden sun" "\n"
2711  "pi: 3.14159" "\n"
2712  "xmas: true" "\n"
2713  "french-hens: 3" "\n"
2714  "calling-birds:" "\n"
2715  " - huey" "\n"
2716  " - dewey" "\n"
2717  " - louie" "\n"
2718  " - fred" "\n"
2719  "xmas-fifth-day:" "\n"
2720  " calling-birds: four" "\n"
2721  " french-hens: 3" "\n"
2722  " golden-rings: 5" "\n"
2723  " partridges:" "\n"
2724  " count: 1" "\n"
2725  " location: a pear tree" "\n"
2726  " turtle-doves: two" "\n"
2727  "cars: GTO" "\n"
2728  "");
2729 
2730  // NOTE: it is good practice to set scalar styles when building
2731  // the tree. See the sample_create_tree_style() below.
2732 }
bool is_seed() const noexcept
true if the object is not invalid and in seed state.
Definition: node.hpp:1136
bool invalid() const noexcept
true if the object is not referring to any existing or seed node.
Definition: node.hpp:1134
C * str
a restricted pointer to the first character of the substring
Definition: substr.hpp:216
real_< T > real(T val, int precision, RealFormat_e fmt=FTOA_FLOAT)
Definition: format.hpp:362
void set_val(csubstr val)
Definition: node.hpp:1251
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition: node.hpp:1062
#define CHECK(predicate)
a testing assertion, used only in this quickstart
Definition: quickstart.cpp:310
boolalpha_ boolalpha(T const &val=false)
tag function to mark a variable to be written as an alphabetic boolean, ie as either true or false ...
Definition: format.hpp:70
csubstr val() const RYML_NOEXCEPT
Forward to Tree::val().
Definition: node.hpp:179
NodeRef append_child()
Definition: node.hpp:1715
void set_serialized(T const &v)
serialize a variable to this node.
Definition: node.hpp:1375
void set_seq()
Definition: node.hpp:1254
void set_map()
Definition: node.hpp:1257
void sample_create_tree_style ( )

set node styles while creating trees

Shows how to set styles when building a tree: this may be needed because you want to control the emitted YAML, but for scalars there is also a performance reason to do this.

Note
You can and should set the style when creating a tree for emitting later. This is because YAML has constraints on which styles can be used for a particular scalar (eg, a plain scalar have leading or trailing whitespace, or if in flow mode it cannot have comma followed by space).
When the scalar is not marked with an explicit style, the ryml emitter adheres to these constraints by scanning each scalar to choose a style for it. On the other hand, if the scalar is marked with an explicit style, the emitter will honor that style, and not do the scan.
So explicitly setting the style for scalars saves the emitter from having to scan each scalar while emitting.
For containers, setting the style does not offer an emit performance improvement like with scalars. Nevertheless, you may still find it useful to control the emitted YAML.

Following this recommendation, ryml also explicitly sets the styles while parsing.

Definition at line 2764 of file quickstart.cpp.

Referenced by main().

2765 {
2766  ryml::Tree tree;
2767  ryml::NodeRef root = tree;
2768  root.set_map(ryml::BLOCK);
2769  // with .set_*() we should use explicit styles (because .set_*()
2770  // only takes csubstr arguments)
2771  root["not plain"].set_val(" with whitespace "); // no style set
2772  root["doe"].set_val("a deer, a female deer", ryml::VAL_PLAIN);
2773  root["ray"].set_val("a drop of golden sun", ryml::VAL_SQUO);
2774  root["me"].set_val("a name I call myself", ryml::VAL_DQUO);
2775  root["far"].set_val("a long long way to go", ryml::VAL_LITERAL);
2776  root["sow"].set_val("a needle pulling thread", ryml::VAL_FOLDED);
2777  root["seq"].set_seq(ryml::FLOW_SL|ryml::FLOW_SPC); // flow, single-line, with spaces after commas
2778  root["map1"].set_map(ryml::FLOW_ML1); // flow, multiline, 1 value per line
2779  root["mapn"].set_map(ryml::FLOW_MLN); // flow, multiline, N values per line, wrapped
2780  // likewise for all of set_serialized(), set_key(),
2781  // set_key_serialized(), save(), save_key(): all these accept the
2782  // style as an extra argument. But when serializing there's a
2783  // nice feature: ryml will automatically set the scalar style to
2784  // VAL_PLAIN / KEY_PLAIN when its type verifies std::is_arithmetic<T>.
2785  for(int i : {0, 1, 2, 3})
2786  {
2787  ryml::NodeRef childseq = root["seq"].append_child();
2788  ryml::NodeRef childmap1 = root["map1"].append_child();
2789  ryml::NodeRef childmapn = root["mapn"].append_child();
2790  // Note how we're NOT setting the style:
2791  childseq.set_serialized(i);
2792  childmap1.set_key_serialized(i + 1);
2793  childmapn.set_key_serialized(i + 1);
2794  childmap1.set_serialized((i + 1) * 10);
2795  childmapn.set_serialized((i + 1) * 10);
2796  // ... and yet ryml has set it to plain:
2797  CHECK(childseq.is_val_plain());
2798  CHECK(childmap1.is_key_plain());
2799  CHECK(childmapn.is_key_plain());
2800  CHECK(childmap1.is_val_plain());
2801  CHECK(childmapn.is_val_plain());
2802  }
2803  // let's see the styles now:
2804  CHECK(ryml::emitrs_yaml<std::string>(tree) ==
2805  // note how this is quoted, without having explicit style
2806  // set. That is because plain scalars cannot have
2807  // leading/trailing whitespace characters. This scalar did
2808  // not have a style set, so during emitting it was scanned
2809  // to determine its style, and so VAL_SQUO was chosen:
2810  "not plain: ' with whitespace '" "\n"
2811  // as for the rest, the style is honored, and the scalars
2812  // are not scanned by the emitter, resulting in a
2813  // performance increase:
2814  "doe: a deer, a female deer" "\n"
2815  "ray: 'a drop of golden sun'" "\n"
2816  "me: \"a name I call myself\"" "\n"
2817  "far: |-" "\n"
2818  " a long long way to go" "\n"
2819  "sow: >-" "\n"
2820  " a needle pulling thread" "\n"
2821  "seq: [0, 1, 2, 3]" "\n"
2822  "map1: {" "\n"
2823  " 1: 10," "\n"
2824  " 2: 20," "\n"
2825  " 3: 30," "\n"
2826  " 4: 40" "\n"
2827  " }" "\n"
2828  "mapn: {" "\n"
2829  " 1: 10,2: 20,3: 30,4: 40" "\n"
2830  " }" "\n"
2831  "");
2832  // Note that it would be an error to set a scalar style
2833  // incompatible with the scalar contents. ryml always honor the
2834  // node style, so it will blindly emit roundtrip-unstable YAML if
2835  // the style is incompatible.
2836  //
2837  // For example, this is incorrect because a plain scalar cannot
2838  // have leading or trailing whitespace:
2839  root["plain"].set_val(" with whitespace ", ryml::VAL_PLAIN); // incorrect.
2840  // note how the whitespace will be lost when parsed:
2841  CHECK(ryml::emitrs_yaml<std::string>(root["plain"]) ==
2842  "plain: with whitespace " "\n"
2843  "");
2844 }
mark val scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:156
bool is_key_plain() const RYML_NOEXCEPT
Forward to Tree::is_key_plain().
Definition: node.hpp:262
mark val scalar as single quoted '
Definition: node_type.hpp:152
mark val scalar as double quoted "
Definition: node_type.hpp:154
mark container with multi-line flow style, n elements per line, < wrapped (as set by EmitOptions::max...
Definition: node_type.hpp:90
void set_val(csubstr val)
Definition: node.hpp:1251
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition: node.hpp:1062
mark val scalar as multiline, block folded >
Definition: node_type.hpp:150
#define CHECK(predicate)
a testing assertion, used only in this quickstart
Definition: quickstart.cpp:310
mark container with block style < - seqs as <
Definition: node_type.hpp:136
mark container with spaces after comma when in flow mode. < Applies to both FLOW_SL and FLOW_MLN (but...
Definition: node_type.hpp:132
bool is_val_plain() const RYML_NOEXCEPT
Forward to Tree::is_val_plain().
Definition: node.hpp:263
mark val scalar as multiline, block literal |
Definition: node_type.hpp:148
NodeRef append_child()
Definition: node.hpp:1715
void set_serialized(T const &v)
serialize a variable to this node.
Definition: node.hpp:1375
void set_key_serialized(T const &k)
serialize a variable, then assign the result to the node's key
Definition: node.hpp:1396
mark container with multi-line flow style, 1 element per line < - seqs as <
Definition: node_type.hpp:75
void set_seq()
Definition: node.hpp:1254
mark container with single-line flow style < - seqs as <
Definition: node_type.hpp:56
void set_map()
Definition: node.hpp:1257
void sample_tree_arena ( )

interact with the tree's serialization arena

demonstrates explicit and implicit interaction with the tree's string arena.

Note that ryml only holds strings in the tree's nodes.

Definition at line 2852 of file quickstart.cpp.

Referenced by main().

2853 {
2854  // mutable buffers are parsed in place:
2855  {
2856  char buf[] = "[a, b, c, d]";
2857  ryml::substr yml = buf;
2858  ryml::Tree tree = ryml::parse_in_place(yml);
2859  // notice the arena is empty:
2860  CHECK(tree.arena().empty());
2861  // and the tree is pointing at the original buffer:
2862  ryml::NodeRef root = tree.rootref();
2863  CHECK(root[0].val().is_sub(yml));
2864  CHECK(root[1].val().is_sub(yml));
2865  CHECK(root[2].val().is_sub(yml));
2866  CHECK(root[3].val().is_sub(yml));
2867  CHECK(yml.is_super(root[0].val()));
2868  CHECK(yml.is_super(root[1].val()));
2869  CHECK(yml.is_super(root[2].val()));
2870  CHECK(yml.is_super(root[3].val()));
2871  }
2872 
2873  // when parsing immutable buffers, the buffer is first copied to the
2874  // tree's arena; the copy in the arena is then the buffer which is
2875  // actually parsed
2876  {
2877  ryml::csubstr yml = "[a, b, c, d]";
2878  ryml::Tree tree = ryml::parse_in_arena(yml);
2879  // notice the buffer was copied to the arena:
2880  CHECK(tree.arena().data() != yml.data());
2881  CHECK(tree.arena() == yml);
2882  // and the tree is pointing at the arena instead of to the
2883  // original buffer:
2884  ryml::NodeRef root = tree.rootref();
2885  ryml::csubstr arena = tree.arena();
2886  CHECK(root[0].val().is_sub(arena));
2887  CHECK(root[1].val().is_sub(arena));
2888  CHECK(root[2].val().is_sub(arena));
2889  CHECK(root[3].val().is_sub(arena));
2890  CHECK(arena.is_super(root[0].val()));
2891  CHECK(arena.is_super(root[1].val()));
2892  CHECK(arena.is_super(root[2].val()));
2893  CHECK(arena.is_super(root[3].val()));
2894  }
2895 
2896  // the arena is also used when the data is serialized to the tree.
2897  // first example: parse in place
2898  {
2899  char buf[] = "[a, b, c, d]"; // mutable
2900  ryml::substr yml = buf;
2901  ryml::Tree tree = ryml::parse_in_place(yml);
2902  // notice the arena is empty:
2903  CHECK(tree.arena().empty());
2904  ryml::NodeRef root = tree.rootref();
2905 
2906  // serialize an integer, and mutate the tree
2907  CHECK(root[2].val() == "c");
2908  CHECK(root[2].val().is_sub(yml)); // val is first pointing at the buffer
2909  root[2].set_serialized(12345);
2910  CHECK(root[2].val() == "12345");
2911  CHECK(root[2].val().is_sub(tree.arena())); // now val is pointing at the arena
2912  // notice the serialized string was appended to the tree's arena:
2913  CHECK(tree.arena() == "12345");
2914 
2915  // serialize an integer, and mutate the tree
2916  CHECK(root[3].val() == "d");
2917  CHECK(root[3].val().is_sub(yml)); // val is first pointing at the buffer
2918  root[3].set_serialized(67890);
2919  CHECK(root[3].val() == "67890");
2920  CHECK(root[3].val().is_sub(tree.arena())); // now val is pointing at the arena
2921  // notice the serialized string was appended to the tree's arena:
2922  CHECK(tree.arena() == "1234567890");
2923  }
2924  // the arena is also used when the data is serialized to string
2925  // second example: parse in arena
2926  {
2927  ryml::csubstr yml = "[a, b, c, d]"; // immutable
2928  ryml::Tree tree = ryml::parse_in_arena(yml);
2929  // notice the buffer was copied to the arena:
2930  CHECK(tree.arena().data() != yml.data());
2931  CHECK(tree.arena() == yml);
2932  ryml::NodeRef root = tree.rootref();
2933 
2934  // serialize an integer, and mutate the tree
2935  CHECK(root[2].val() == "c");
2936  root[2].set_serialized(12345); // serialize an integer
2937  CHECK(root[2].val() == "12345");
2938  // notice the serialized string was appended to the tree's arena:
2939  // notice also the previous values remain there.
2940  // RYML DOES NOT KEEP TRACK OF REFERENCES TO THE ARENA.
2941  CHECK(tree.arena() == "[a, b, c, d]12345");
2942  // old values: --------------^
2943 
2944  // serialize an integer, and mutate the tree
2945  root[3].set_serialized(67890);
2946  CHECK(root[3].val() == "67890");
2947  // notice the serialized string was appended to the tree's arena:
2948  // notice also the previous values remain there.
2949  // RYML DOES NOT KEEP TRACK OF REFERENCES TO THE ARENA.
2950  CHECK(tree.arena() == "[a, b, c, d]1234567890");
2951  // old values: --------------^ ---^^^^^
2952  }
2953 
2954  // to_arena(): directly serialize values to the arena:
2955  {
2956  ryml::Tree tree = ryml::parse_in_arena("{a: b}");
2957  ryml::csubstr c10 = tree.to_arena(10101010);
2958  CHECK(c10 == "10101010");
2959  CHECK(c10.is_sub(tree.arena()));
2960  CHECK(tree.arena() == "{a: b}10101010");
2961  CHECK(tree.key(1) == "a");
2962  CHECK(tree.val(1) == "b");
2963  tree.set_val(1, c10);
2964  CHECK(tree.val(1) == c10);
2965  // and you can also do it through a node:
2966  ryml::NodeRef root = tree.rootref();
2967  root["a"].set_serialized(2222);
2968  CHECK(root["a"].val() == "2222");
2969  CHECK(tree.arena() == "{a: b}101010102222");
2970  }
2971 
2972  // copy_to_arena(): manually copy a string to the arena:
2973  {
2974  ryml::Tree tree = ryml::parse_in_arena("{a: b}");
2975  ryml::csubstr mystr = "Gosset Grande Reserve";
2976  ryml::csubstr copied = tree.copy_to_arena(mystr);
2977  CHECK(!copied.overlaps(mystr));
2978  CHECK(copied == mystr);
2979  CHECK(tree.arena() == "{a: b}Gosset Grande Reserve");
2980  }
2981 
2982  // alloc_arena(): allocate a buffer from the arena:
2983  {
2984  ryml::Tree tree = ryml::parse_in_arena("{a: b}");
2985  ryml::csubstr mystr = "Gosset Grande Reserve";
2986  ryml::substr copied = tree.alloc_arena(mystr.size());
2987  CHECK(!copied.overlaps(mystr));
2988  memcpy(copied.str, mystr.str, mystr.len);
2989  CHECK(copied == mystr);
2990  CHECK(tree.arena() == "{a: b}Gosset Grande Reserve");
2991  }
2992 
2993  // reserve_arena(): ensure the arena has a certain size to avoid reallocations
2994  {
2995  ryml::Tree tree = ryml::parse_in_arena("{a: b}");
2996  CHECK(tree.arena().size() == strlen("{a: b}"));
2997  tree.reserve_arena(100);
2998  CHECK(tree.arena_capacity() >= 100);
2999  CHECK(tree.arena().size() == strlen("{a: b}"));
3000  tree.to_arena(123456);
3001  CHECK(tree.arena().first(12) == "{a: b}123456");
3002  }
3003 }
csubstr const & key(id_type node) const
Definition: tree.hpp:454
csubstr const & val(id_type node) const
Definition: tree.hpp:460
void set_val(id_type node, csubstr val) RYML_NOEXCEPT
Definition: tree.hpp:688
bool is_super(ro_substr const that) const noexcept
true if that is a substring of *this (ie, from the same buffer)
Definition: substr.hpp:484
bool overlaps(ro_substr const that) const noexcept
true if there is overlap of at least one element between that and *this
Definition: substr.hpp:493
substr copy_to_arena(csubstr s)
copy the given string to the tree's arena, growing the arena by the required size.
Definition: tree.hpp:1370
C * str
a restricted pointer to the first character of the substring
Definition: substr.hpp:216
csubstr arena() const
get the current arena
Definition: tree.hpp:1317
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
Definition: substr.hpp:529
C * data() noexcept
Definition: substr.hpp:366
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *tree, id_type node_id)
(1) parse YAML into an existing tree node. The filename will be used in any error messages arising du...
Definition: parse.cpp:209
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition: node.hpp:1062
size_t arena_capacity() const
get the current capacity of the tree's internal arena
Definition: tree.hpp:1311
size_t size() const noexcept
Definition: substr.hpp:358
void reserve_arena(size_t arena_cap=RYML_DEFAULT_TREE_ARENA_CAPACITY)
ensure the tree's internal string arena is at least the given capacity
Definition: tree.hpp:1409
#define CHECK(predicate)
a testing assertion, used only in this quickstart
Definition: quickstart.cpp:310
size_t len
the length of the substring
Definition: substr.hpp:218
NodeRef rootref()
Get the root as a NodeRef . Note that a non-const Tree implicitly converts to NodeRef.
Definition: tree.cpp:56
bool empty() const noexcept
Definition: substr.hpp:356
substr alloc_arena(size_t sz)
grow the tree's string arena by the given size and return a substr of the added portion ...
Definition: tree.hpp:1397
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *tree, id_type node_id)
(1) parse YAML into an existing tree node.
Definition: parse.cpp:165
void set_serialized(T const &v)
serialize a variable to this node.
Definition: node.hpp:1375
csubstr to_arena(T const &a)
serialize the given variable to the tree's arena, growing it as needed to accomodate the serializatio...
Definition: tree.hpp:1349
bool is_sub(ro_substr const that) const noexcept
true if *this is a substring of that (ie, from the same buffer)
Definition: substr.hpp:478