rapidyaml 0.16.0
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
Parsing

Functions

void sample_parse_file ()
 ready-to-go example of parsing a file from disk
void sample_parse_in_place ()
 parse a mutable YAML source buffer
void sample_parse_in_arena ()
 parse a read-only YAML source buffer
void sample_parse_reuse_tree ()
 parse into an existing tree, maybe into a node
void sample_parse_reuse_parser ()
 reuse an existing parser
void sample_parse_reuse_tree_and_parser ()
 how to reuse existing trees and parsers
void sample_parse_style ()
 shows how rapidyaml retains the style of parsed YAML

Detailed Description

Function Documentation

◆ sample_parse_file()

void sample_parse_file ( )

ready-to-go example of parsing a file from disk

demonstrate how to load a YAML file from disk to parse with ryml.

ryml offers no overload to directly parse files from disk; it only parses source buffers (which may be mutable or immutable). It is up to the caller to first load the file contents into a buffer before parsing with ryml. To help with this you can use the (efficient) helper [file_get_contents](c4::yml::file_get_contents()). See also the analogous file_put_contents

See also
Parse utilities

Definition at line 1951 of file quickstart.cpp.

1952{
1953 const char filename[] = "ryml_example.yml";
1954 std::string yaml = ""
1955 "foo: 1" "\n"
1956 "bar:" "\n"
1957 "- 2" "\n"
1958 "- 3" "\n";
1959 // because this is a minimal sample, it assumes nothing on the
1960 // environment/OS (other than that it can read/write files). So we
1961 // create the file on the fly:
1962 ryml::file_put_contents(yaml, filename);
1963
1964 // now we can load it into a std::string (for example):
1965 {
1966 std::string contents = ryml::file_get_contents<std::string>(filename);
1967 ryml::Tree tree = ryml::parse_in_arena(ryml::to_csubstr(contents)); // immutable (csubstr) overload
1968 CHECK(tree["foo"].val() == "1");
1969 CHECK(tree["bar"][0].val() == "2");
1970 CHECK(tree["bar"][1].val() == "3");
1971 }
1972
1973 // or we can use a vector<char> instead:
1974 {
1975 std::vector<char> contents = ryml::file_get_contents<std::vector<char>>(filename);
1976 ryml::Tree tree = ryml::parse_in_place(ryml::to_substr(contents)); // mutable (substr) overload
1977 CHECK(tree["foo"].val() == "1");
1978 CHECK(tree["bar"][0].val() == "2");
1979 CHECK(tree["bar"][1].val() == "3");
1980 }
1981
1982 // generally, any contiguous char container can be used with ryml,
1983 // provided that the ryml::substr/ryml::csubstr view can be
1984 // created out of it.
1985 //
1986 // ryml provides the overloads above for these two containers, but
1987 // if you are using another container it should be very easy (only
1988 // requires pointer and length).
1989}
void file_get_contents(const char *filename, FILE *fp, size_t filesz, void *buf, size_t bufsz)
load a file of specified size from disk into an existing contiguous buffer.
Definition file.hpp:106
void file_put_contents(void const *buf, size_t sz, FILE *file, const char *filename=nullptr)
save a contiguous buffer into a file
Definition file.hpp:57
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
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
#define CHECK(predicate)
a testing assertion, used only in this quickstart
substr to_substr(char(&s)[N]) noexcept
Definition substr.hpp:2376
csubstr to_csubstr(const char(&s)[N]) noexcept
Definition substr.hpp:2380

Referenced by main().

◆ sample_parse_in_place()

void sample_parse_in_place ( )

parse a mutable YAML source buffer

demonstrate in-place parsing of a mutable YAML source buffer.

See also
Parse utilities

Definition at line 1996 of file quickstart.cpp.

1997{
1998 // Like the name suggests, parse_in_place() directly mutates the
1999 // source buffer in place
2000 char src[] = "{foo: 1, bar: [2, 3]}"; // ryml can parse in situ
2001 ryml::substr srcview = src; // a mutable view to the source buffer
2002 ryml::Tree tree = ryml::parse_in_place(srcview); // you can also reuse the tree and/or parser
2003 ryml::ConstNodeRef root = tree.crootref(); // get a constant reference to the root
2004
2005 CHECK(root.is_map());
2006 CHECK(root["foo"].is_keyval());
2007 CHECK(root["foo"].key() == "foo");
2008 CHECK(root["foo"].val() == "1");
2009 CHECK(root["bar"].is_seq());
2010 CHECK(root["bar"].has_key());
2011 CHECK(root["bar"].key() == "bar");
2012 CHECK(root["bar"][0].val() == "2");
2013 CHECK(root["bar"][1].val() == "3");
2014
2015 // deserializing:
2016 int foo = 0, bar0 = 0, bar1 = 0;
2017 root["foo"].load(&foo);
2018 root["bar"][0].load(&bar0);
2019 root["bar"][1].load(&bar1);
2020 CHECK(foo == 1);
2021 CHECK(bar0 == 2);
2022 CHECK(bar1 == 3);
2023
2024 // after parsing, the tree holds views to the source buffer:
2025 CHECK(root["foo"].val().data() == src + strlen("{foo: "));
2026 CHECK(root["foo"].val().begin() == src + strlen("{foo: "));
2027 CHECK(root["foo"].val().end() == src + strlen("{foo: 1"));
2028 CHECK(root["foo"].val().is_sub(srcview)); // equivalent to the previous three assertions
2029 CHECK(root["bar"][0].val().data() == src + strlen("{foo: 1, bar: ["));
2030 CHECK(root["bar"][0].val().begin() == src + strlen("{foo: 1, bar: ["));
2031 CHECK(root["bar"][0].val().end() == src + strlen("{foo: 1, bar: [2"));
2032 CHECK(root["bar"][0].val().is_sub(srcview)); // equivalent to the previous three assertions
2033 CHECK(root["bar"][1].val().data() == src + strlen("{foo: 1, bar: [2, "));
2034 CHECK(root["bar"][1].val().begin() == src + strlen("{foo: 1, bar: [2, "));
2035 CHECK(root["bar"][1].val().end() == src + strlen("{foo: 1, bar: [2, 3"));
2036 CHECK(root["bar"][1].val().is_sub(srcview)); // equivalent to the previous three assertions
2037
2038 // NOTE. parse_in_place() cannot accept ryml::csubstr
2039 // so this will cause a /compile/ error:
2040 ryml::csubstr csrcview = srcview; // ok, can assign from mutable to immutable
2041 //tree = ryml::parse_in_place(csrcview); // compile error, cannot mutate an immutable view
2042 (void)csrcview;
2043}
Holds a pointer to an existing tree, and a node id.
Definition node.hpp:737
ConstNodeRef crootref() const
Get the root as a ConstNodeRef . Note that Tree implicitly converts to ConstNodeRef.
Definition tree.cpp:65
basic_substring< char > substr
a mutable string view
Definition substr.hpp:2355
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2356
bool is_map() const RYML_NOEXCEPT
Forward to Tree::is_map().
Definition node.hpp:207
void load(T *v, bool check_readable=true) const
(1) deserialize the node's contents (val or container) to the given variable, forwarding to the user-...
Definition node.hpp:345

Referenced by main().

◆ sample_parse_in_arena()

void sample_parse_in_arena ( )

parse a read-only YAML source buffer

demonstrate parsing of a read-only YAML source buffer

See also
Parse utilities

Definition at line 2050 of file quickstart.cpp.

2051{
2052 // to parse read-only memory, ryml will copy first to the tree's
2053 // arena, and then parse the copied buffer:
2054 ryml::Tree tree = ryml::parse_in_arena("{foo: 1, bar: [2, 3]}");
2055 ryml::ConstNodeRef root = tree.crootref(); // get a const reference to the root
2056
2057 CHECK(root.is_map());
2058 CHECK(root["foo"].is_keyval());
2059 CHECK(root["foo"].key() == "foo");
2060 CHECK(root["foo"].val() == "1");
2061 CHECK(root["bar"].is_seq());
2062 CHECK(root["bar"].has_key());
2063 CHECK(root["bar"].key() == "bar");
2064 CHECK(root["bar"][0].val() == "2");
2065 CHECK(root["bar"][1].val() == "3");
2066
2067 // deserializing:
2068 int foo = 0, bar0 = 0, bar1 = 0;
2069 root["foo"].load(&foo);
2070 root["bar"][0].load(&bar0);
2071 root["bar"][1].load(&bar1);
2072 CHECK(foo == 1);
2073 CHECK(bar0 == 2);
2074 CHECK(bar1 == 3);
2075
2076 // NOTE. parse_in_arena() cannot accept ryml::substr. Overloads
2077 // receiving substr buffers are declared, but intentionally left
2078 // undefined, so this will cause a /linker/ error
2079 char src[] = "{foo: is it really true}";
2080 ryml::substr srcview = src;
2081 //tree = ryml::parse_in_place(srcview); // linker error, overload intentionally undefined
2082
2083 // If you really intend to parse a mutable buffer in the arena,
2084 // then simply convert it to immutable prior to calling
2085 // parse_in_arena():
2086 ryml::csubstr csrcview = srcview; // assigning from src also works
2087 tree = ryml::parse_in_arena(csrcview); // OK! csrcview is immutable
2088 CHECK(tree["foo"].val() == "is it really true");
2089}

Referenced by main().

◆ sample_parse_reuse_tree()

void sample_parse_reuse_tree ( )

parse into an existing tree, maybe into a node

demonstrate reuse/modification of tree when parsing

See also
Parse utilities

Definition at line 2096 of file quickstart.cpp.

2097{
2098 ryml::Tree tree;
2099
2100 // it will always be faster if the tree's size is conveniently reserved:
2101 tree.reserve(30); // reserve 30 nodes (good enough for this sample)
2102 // if you are using the tree's arena to serialize data,
2103 // then reserve also the arena's size:
2104 tree.reserve_arena(256); // reserve 256 characters (good enough for this sample)
2105
2106 // now parse into the tree:
2107 ryml::csubstr yaml = ""
2108 "foo: 1" "\n"
2109 "bar: [2,3]" "\n"
2110 "";
2111 ryml::parse_in_arena(yaml, &tree);
2112
2113 ryml::ConstNodeRef root = tree.crootref();
2114 CHECK(root.num_children() == 2);
2115 CHECK(root.is_map());
2116 CHECK(root["foo"].is_keyval());
2117 CHECK(root["foo"].key() == "foo");
2118 CHECK(root["foo"].val() == "1");
2119 CHECK(root["bar"].is_seq());
2120 CHECK(root["bar"].has_key());
2121 CHECK(root["bar"].key() == "bar");
2122 CHECK(root["bar"][0].val() == "2");
2123 CHECK(root["bar"][1].val() == "3");
2125
2126 // WATCHOUT: parsing into an existing tree will APPEND to it:
2127 ryml::parse_in_arena("{foo2: 12, bar2: [22, 32]}", &tree);
2129 "foo: 1" "\n"
2130 "bar: [2,3]" "\n"
2131 "foo2: 12" "\n"
2132 "bar2: [22,32]" "\n"
2133 "");
2134 CHECK(root.num_children() == 4);
2135 CHECK(root["foo2"].is_keyval());
2136 CHECK(root["foo2"].key() == "foo2");
2137 CHECK(root["foo2"].val() == "12");
2138 CHECK(root["bar2"].is_seq());
2139 CHECK(root["bar2"].has_key());
2140 CHECK(root["bar2"].key() == "bar2");
2141 CHECK(root["bar2"][0].val() == "22");
2142 CHECK(root["bar2"][1].val() == "32");
2143
2144 // if you want to fully replace the tree, you need to clear first
2145 // before parsing into an existing tree:
2146 tree.clear();
2147 tree.clear_arena(); // you may or may not want to clear the arena
2148 ryml::parse_in_arena("- a\n- b\n- {x0: 1, x1: 2}", &tree);
2149 CHECK(ryml::emitrs_yaml<std::string>(tree) == "- a\n- b\n- {x0: 1,x1: 2}\n");
2150 CHECK(root.is_seq());
2151 CHECK(root[0].val() == "a");
2152 CHECK(root[1].val() == "b");
2153 CHECK(root[2].is_map());
2154 CHECK(root[2]["x0"].val() == "1");
2155 CHECK(root[2]["x1"].val() == "2");
2156
2157 // we can parse directly into a node nested deep in an existing tree:
2158 ryml::NodeRef mroot = tree.rootref(); // modifiable root
2159 ryml::parse_in_arena("champagne: Dom Perignon\ncoffee: Arabica", mroot.append_child());
2161 "- a" "\n"
2162 "- b" "\n"
2163 "- {x0: 1,x1: 2}" "\n"
2164 "- champagne: Dom Perignon" "\n"
2165 " coffee: Arabica" "\n"
2166 "");
2167 CHECK(root.is_seq());
2168 CHECK(root[0].val() == "a");
2169 CHECK(root[1].val() == "b");
2170 CHECK(root[2].is_map());
2171 CHECK(root[2]["x0"].val() == "1");
2172 CHECK(root[2]["x1"].val() == "2");
2173 CHECK(root[3].is_map());
2174 CHECK(root[3]["champagne"].val() == "Dom Perignon");
2175 CHECK(root[3]["coffee"].val() == "Arabica");
2176
2177 mroot[3]["more"].set_map();
2178 mroot[3]["beer"].set_seq();
2179 CHECK(mroot[3]["more"].readable());
2180 CHECK(mroot[3]["more"].key() == "more");
2181 CHECK(mroot[3]["more"].is_map());
2182 CHECK(!mroot[3]["more"].is_val());
2183 ryml::parse_in_arena("{vinho verde: Soalheiro, vinho tinto: Redoma 2017}", mroot[3]["more"]);
2184 ryml::parse_in_arena("- Rochefort 10\n- Busch\n- Leffe Rituel", mroot[3]["beer"]);
2185 ryml::parse_in_arena("lots\nof\nwater", mroot[3]["always"]);
2187 "- a" "\n"
2188 "- b" "\n"
2189 "- {x0: 1,x1: 2}" "\n"
2190 "- champagne: Dom Perignon" "\n"
2191 " coffee: Arabica" "\n"
2192 // note these were added:
2193 " more:" "\n"
2194 " vinho verde: Soalheiro" "\n"
2195 " vinho tinto: Redoma 2017" "\n"
2196 " beer:" "\n"
2197 " - Rochefort 10" "\n"
2198 " - Busch" "\n"
2199 " - Leffe Rituel" "\n"
2200 " always: lots of water" "\n"
2201 "");
2202
2203 // can append at the top:
2204 ryml::parse_in_arena("- foo\n- bar\n- baz\n- bat", mroot);
2206 "- a" "\n"
2207 "- b" "\n"
2208 "- {x0: 1,x1: 2}" "\n"
2209 "- champagne: Dom Perignon" "\n"
2210 " coffee: Arabica" "\n"
2211 " more:" "\n"
2212 " vinho verde: Soalheiro" "\n"
2213 " vinho tinto: Redoma 2017" "\n"
2214 " beer:" "\n"
2215 " - Rochefort 10" "\n"
2216 " - Busch" "\n"
2217 " - Leffe Rituel" "\n"
2218 " always: lots of water" "\n"
2219 // note these were added
2220 "- foo" "\n"
2221 "- bar" "\n"
2222 "- baz" "\n"
2223 "- bat" "\n"
2224 "");
2225
2226 // or nested:
2227 ryml::parse_in_arena("[Kasteel Donker]", mroot[3]["beer"]);
2229 "- a" "\n"
2230 "- b" "\n"
2231 "- {x0: 1,x1: 2}" "\n"
2232 "- champagne: Dom Perignon" "\n"
2233 " coffee: Arabica" "\n"
2234 " more:" "\n"
2235 " vinho verde: Soalheiro" "\n"
2236 " vinho tinto: Redoma 2017" "\n"
2237 " beer:" "\n"
2238 " - Rochefort 10" "\n"
2239 " - Busch" "\n"
2240 " - Leffe Rituel" "\n"
2241 " - Kasteel Donker" "\n" // added this
2242 " always: lots of water" "\n"
2243 "- foo" "\n"
2244 "- bar" "\n"
2245 "- baz" "\n"
2246 "- bat" "\n"
2247 "");
2248}
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition node.hpp:1063
NodeRef append_child()
Definition node.hpp:1715
void clear()
clear the tree and zero every node
Definition tree.cpp:330
NodeRef rootref()
Get the root as a NodeRef . Note that a non-const Tree implicitly converts to NodeRef.
Definition tree.cpp:56
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
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
Definition tree.cpp:292
void clear_arena()
Definition tree.hpp:340
substr emitrs_yaml(Tree const &t, id_type id, EmitOptions const &opts, CharOwningContainer *cont, bool append=false)
(1) emit+resize: emit YAML to the given std::string/std::vector<char>-like container,...
id_type num_children() const RYML_NOEXCEPT
O(num_children).
Definition node.hpp:302
bool is_seq() const RYML_NOEXCEPT
Forward to Tree::is_seq().
Definition node.hpp:208

Referenced by main().

◆ sample_parse_reuse_parser()

void sample_parse_reuse_parser ( )

reuse an existing parser

Demonstrates reuse of an existing parser.

Doing this is recommended when multiple files are parsed.

See also
Parse utilities

Definition at line 2256 of file quickstart.cpp.

2257{
2258 ryml::EventHandlerTree evt_handler = {};
2259 ryml::Parser parser(&evt_handler);
2260
2261 // it is also advised to reserve the parser depth
2262 // to the expected depth of the data tree:
2263 parser.reserve_stack(10); // uses small storage optimization
2264 // defaulting to 16 depth, so this
2265 // instruction is a no-op, and the stack
2266 // will located in the parser object.
2267 parser.reserve_stack(20); // But this will cause an allocation
2268 // because it is above 16.
2269
2270 ryml::csubstr yaml = "[Dom Perignon,Gosset Grande Reserve,Jacquesson 742]";
2271 ryml::Tree champagnes = parse_in_arena(&parser, "champagnes.yml", yaml);
2272 CHECK(ryml::emitrs_yaml<std::string>(champagnes) == yaml);
2273
2274 yaml = "[Rochefort 10,Busch,Leffe Rituel,Kasteel Donker]";
2275 ryml::Tree beers = parse_in_arena(&parser, "beers.yml", yaml);
2276 CHECK(ryml::emitrs_yaml<std::string>(beers) == yaml);
2277}
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree (see Event Ha...
Definition fwd.hpp:19
The event handler to create a ryml Tree.

Referenced by main().

◆ sample_parse_reuse_tree_and_parser()

void sample_parse_reuse_tree_and_parser ( )

how to reuse existing trees and parsers

for ultimate speed when parsing multiple times, reuse both the tree and parser

See also
Parse utilities

Definition at line 2285 of file quickstart.cpp.

2286{
2287 ryml::Tree tree;
2288 // it will always be faster if the tree's size is conveniently reserved:
2289 tree.reserve(30); // reserve 30 nodes (good enough for this sample)
2290 // if you are using the tree's arena to serialize data,
2291 // then reserve also the arena's size:
2292 tree.reserve(256); // reserve 256 characters (good enough for this sample)
2293
2294 ryml::EventHandlerTree evt_handler;
2295 ryml::Parser parser(&evt_handler);
2296 // it is also advised to reserve the parser depth
2297 // to the expected depth of the data tree:
2298 parser.reserve_stack(10); // the parser uses small storage
2299 // optimization defaulting to 16 depth,
2300 // so this instruction is a no-op, and
2301 // the stack will be located in the
2302 // parser object.
2303 parser.reserve_stack(20); // But this will cause an allocation
2304 // because it is above 16.
2305
2306 ryml::csubstr champagnes = ""
2307 "- Dom Perignon\n"
2308 "- Gosset Grande Reserve\n"
2309 "- Jacquesson 742\n"
2310 "";
2311 ryml::csubstr beers = ""
2312 "- Rochefort 10\n"
2313 "- Busch\n"
2314 "- Leffe Rituel\n"
2315 "- Kasteel Donker\n"
2316 "";
2317 ryml::csubstr wines = ""
2318 "- Soalheiro\n"
2319 "- Niepoort Redoma 2017\n"
2320 "- Vina Esmeralda\n"
2321 "";
2322
2323 parse_in_arena(&parser, "champagnes.yml", champagnes, &tree);
2324 CHECK(ryml::emitrs_yaml<std::string>(tree) == champagnes);
2325
2326 // watchout: this will APPEND to the given tree:
2327 parse_in_arena(&parser, "beers.yml", beers, &tree);
2329 "- Dom Perignon\n"
2330 "- Gosset Grande Reserve\n"
2331 "- Jacquesson 742\n"
2332 "- Rochefort 10\n"
2333 "- Busch\n"
2334 "- Leffe Rituel\n"
2335 "- Kasteel Donker\n"
2336 "");
2337
2338 // if you don't wish to append, clear the tree first:
2339 tree.clear();
2340 parse_in_arena(&parser, "wines.yml", wines, &tree);
2342 "- Soalheiro\n"
2343 "- Niepoort Redoma 2017\n"
2344 "- Vina Esmeralda\n"
2345 "");
2346}

Referenced by main().

◆ sample_parse_style()

void sample_parse_style ( )

shows how rapidyaml retains the style of parsed YAML

shows how rapidyaml marks the tree nodes with their original style in the parsed YAML.

See also
Tree utilities
Node classes

Definition at line 2357 of file quickstart.cpp.

2358{
2359 ryml::csubstr yaml = ""
2360 "doe: a deer, a female deer" "\n"
2361 "ray: 'a drop of golden sun'" "\n"
2362 "me: \"a name I call myself\"" "\n"
2363 "far: |-" "\n"
2364 " a long long way to go" "\n"
2365 "sow: >-" "\n"
2366 " a needle pulling thread" "\n"
2367 "seq: [0,1,2,3]" "\n"
2368 "map: {" "\n"
2369 " 0: 10," "\n"
2370 " 1: 11," "\n"
2371 " 2: 12," "\n"
2372 " 3: 13" "\n"
2373 " }" "\n"
2374 "";
2375 const ryml::Tree tree = ryml::parse_in_arena(yaml);
2376 // note how every node is tagged with its original style:
2377 CHECK(tree["doe"].is_val_plain());
2378 CHECK(tree["ray"].is_val_squo());
2379 CHECK(tree["me"].is_val_dquo());
2380 CHECK(tree["far"].is_val_literal());
2381 CHECK(tree["sow"].is_val_folded());
2382 CHECK(tree["seq"].is_flow());
2383 CHECK(tree["seq"].is_flow_sl());
2384 CHECK(tree["map"].is_flow());
2385 CHECK(tree["map"].is_flow_mlx());
2386 CHECK(tree.rootref().is_block());
2387 // ... which results in roundtrip-stable YAML:
2389}
bool is_block() const RYML_NOEXCEPT
Forward to Tree::is_block().
Definition node.hpp:242

Referenced by main().