rapidyaml 0.15.2
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 1949 of file quickstart.cpp.

1950{
1951 const char filename[] = "ryml_example.yml";
1952 std::string yaml = ""
1953 "foo: 1" "\n"
1954 "bar:" "\n"
1955 "- 2" "\n"
1956 "- 3" "\n";
1957 // because this is a minimal sample, it assumes nothing on the
1958 // environment/OS (other than that it can read/write files). So we
1959 // create the file on the fly:
1960 ryml::file_put_contents(yaml, filename);
1961
1962 // now we can load it into a std::string (for example):
1963 {
1964 std::string contents = ryml::file_get_contents<std::string>(filename);
1965 ryml::Tree tree = ryml::parse_in_arena(ryml::to_csubstr(contents)); // immutable (csubstr) overload
1966 CHECK(tree["foo"].val() == "1");
1967 CHECK(tree["bar"][0].val() == "2");
1968 CHECK(tree["bar"][1].val() == "3");
1969 }
1970
1971 // or we can use a vector<char> instead:
1972 {
1973 std::vector<char> contents = ryml::file_get_contents<std::vector<char>>(filename);
1974 ryml::Tree tree = ryml::parse_in_place(ryml::to_substr(contents)); // mutable (substr) overload
1975 CHECK(tree["foo"].val() == "1");
1976 CHECK(tree["bar"][0].val() == "2");
1977 CHECK(tree["bar"][1].val() == "3");
1978 }
1979
1980 // generally, any contiguous char container can be used with ryml,
1981 // provided that the ryml::substr/ryml::csubstr view can be
1982 // created out of it.
1983 //
1984 // ryml provides the overloads above for these two containers, but
1985 // if you are using another container it should be very easy (only
1986 // requires pointer and length).
1987}
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 1994 of file quickstart.cpp.

1995{
1996 // Like the name suggests, parse_in_place() directly mutates the
1997 // source buffer in place
1998 char src[] = "{foo: 1, bar: [2, 3]}"; // ryml can parse in situ
1999 ryml::substr srcview = src; // a mutable view to the source buffer
2000 ryml::Tree tree = ryml::parse_in_place(srcview); // you can also reuse the tree and/or parser
2001 ryml::ConstNodeRef root = tree.crootref(); // get a constant reference to the root
2002
2003 CHECK(root.is_map());
2004 CHECK(root["foo"].is_keyval());
2005 CHECK(root["foo"].key() == "foo");
2006 CHECK(root["foo"].val() == "1");
2007 CHECK(root["bar"].is_seq());
2008 CHECK(root["bar"].has_key());
2009 CHECK(root["bar"].key() == "bar");
2010 CHECK(root["bar"][0].val() == "2");
2011 CHECK(root["bar"][1].val() == "3");
2012
2013 // deserializing:
2014 int foo = 0, bar0 = 0, bar1 = 0;
2015 root["foo"].load(&foo);
2016 root["bar"][0].load(&bar0);
2017 root["bar"][1].load(&bar1);
2018 CHECK(foo == 1);
2019 CHECK(bar0 == 2);
2020 CHECK(bar1 == 3);
2021
2022 // after parsing, the tree holds views to the source buffer:
2023 CHECK(root["foo"].val().data() == src + strlen("{foo: "));
2024 CHECK(root["foo"].val().begin() == src + strlen("{foo: "));
2025 CHECK(root["foo"].val().end() == src + strlen("{foo: 1"));
2026 CHECK(root["foo"].val().is_sub(srcview)); // equivalent to the previous three assertions
2027 CHECK(root["bar"][0].val().data() == src + strlen("{foo: 1, bar: ["));
2028 CHECK(root["bar"][0].val().begin() == src + strlen("{foo: 1, bar: ["));
2029 CHECK(root["bar"][0].val().end() == src + strlen("{foo: 1, bar: [2"));
2030 CHECK(root["bar"][0].val().is_sub(srcview)); // equivalent to the previous three assertions
2031 CHECK(root["bar"][1].val().data() == src + strlen("{foo: 1, bar: [2, "));
2032 CHECK(root["bar"][1].val().begin() == src + strlen("{foo: 1, bar: [2, "));
2033 CHECK(root["bar"][1].val().end() == src + strlen("{foo: 1, bar: [2, 3"));
2034 CHECK(root["bar"][1].val().is_sub(srcview)); // equivalent to the previous three assertions
2035
2036 // NOTE. parse_in_place() cannot accept ryml::csubstr
2037 // so this will cause a /compile/ error:
2038 ryml::csubstr csrcview = srcview; // ok, can assign from mutable to immutable
2039 //tree = ryml::parse_in_place(csrcview); // compile error, cannot mutate an immutable view
2040 (void)csrcview;
2041}
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 2048 of file quickstart.cpp.

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

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 2094 of file quickstart.cpp.

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

2255{
2256 ryml::EventHandlerTree evt_handler = {};
2257 ryml::Parser parser(&evt_handler);
2258
2259 // it is also advised to reserve the parser depth
2260 // to the expected depth of the data tree:
2261 parser.reserve_stack(10); // uses small storage optimization
2262 // defaulting to 16 depth, so this
2263 // instruction is a no-op, and the stack
2264 // will located in the parser object.
2265 parser.reserve_stack(20); // But this will cause an allocation
2266 // because it is above 16.
2267
2268 ryml::csubstr yaml = "[Dom Perignon,Gosset Grande Reserve,Jacquesson 742]";
2269 ryml::Tree champagnes = parse_in_arena(&parser, "champagnes.yml", yaml);
2270 CHECK(ryml::emitrs_yaml<std::string>(champagnes) == yaml);
2271
2272 yaml = "[Rochefort 10,Busch,Leffe Rituel,Kasteel Donker]";
2273 ryml::Tree beers = parse_in_arena(&parser, "beers.yml", yaml);
2274 CHECK(ryml::emitrs_yaml<std::string>(beers) == yaml);
2275}
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 2283 of file quickstart.cpp.

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

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 2355 of file quickstart.cpp.

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

Referenced by main().