rapidyaml  0.16.0
parseandemitYAML,anddoitfast
doxy_changelog.md
Go to the documentation of this file.
1 @page Changelog Changelog
2 @tableofcontents
3 
4 ## Current
5 Changes since latest release: [current.md](https://github.com/biojppm/rapidyaml/blob/master/changelog/current.md)
6 
7 
8 
9 ----------------------------
10 <a name="v0.16.0"></a>
11 ## 0.16.0
12 
13 [Github release: 0.16.2](https://github.com/biojppm/rapidyaml/releases/tag/v0.16.0)
14 ### TL;DR
15 This release focuses on API cleaning and tidying, **in preparation of release 1.0**:
16 
17  - improves tracking of nodes causing deserialization errors
18  - adds serialization to/from `Tree` (not just `NodeRef`/`ConstNodeRef`)
19  - deprecates a good number of functions, mostly around serialization and tree/node building
20  - **brings code coverage to 100%** (rounded from >99.5%)
21  - remove the c4core submodule, vendoring-in just the required c4core source code.
22 
23 Significant effort went into maintaining backward compatibility. Nevertheless the API cleanup introduces a number of deprecations, and some other opt-in but recommended changes: see the migration guide in the next section.
24 
25 Finally there are other fixes and improvements. For the details refer to this release's [full changelog](#v016changelogsection), below the migration guide.
26 
27 
28 
29 ### Migration guide
30 
31 This is the list of migration changes, linking to the relevant section below:
32 
33  - [Deprecated `.to_val()` method family for tree building](#toval)
34  - Deprecated operators (but define `RYML_WITH_LEGACY_OPERATORS` to avoid the deprecation):
35  - tree building: [deprecate operators `|=` or `=`](#notequal)
36  - serialization: [deprecate operators `<<` or `>>`](#notshift)
37  - Optional but **recommended**:
38  - [user-implemented `read()` should now return `ReadResult`](#readresult)
39  - [user-implemented `read()`/`write()` should now receive `Tree` and id](#treeid)
40  - [do not use `.load()` (former `>>`) inside `read()`](#noloadinread)
41  - [use `.deserialize_child()` inside `read()`](#deserializechild)
42 
43 Be sure to also read through the quickstart diff for the full overview on how the new features work.
44 
45 > [!TIP]
46 > Hint to see what changed in the quickstart: run `git diff v0.15.2...v0.16.0 samples/quickstart.cpp` on an up-to-date repo clone.
47 
48 
49 <a id="toval"></a>
50 #### Deprecate `.to_val()` family
51 
52 For tree building, methods `.to_*()` were deprecated in favour of the newly-added `.set_*()` methods. See next section.
53 
54 
55 <a id="notequal"></a>
56 #### Deprecate operators |= and =
57 
58 For tree building, `operator|=` and `operator=` were deprecated in favour of the newly-added `.set_*()` methods:
59 
60 @code{c++}
61 c4::yml::Tree tree = ...;
62 c4::yml::id_type node_id = ...;
63 c4::yml::NodeRef node = ...;
64 
65 // before (deprecated)
66 node |= MAP|BLOCK;
67 node["key"] = "val";
68 node["key"] |= VAL_SQUO;
69 node["seq"] |= SEQ|FLOW;
70 node["seq2"] |= SEQ;
71 node.append_child().to_seq("map");
72 
73 // now, same as above:
74 node.set_map(BLOCK);
75 node["key"].set_val("val", VAL_SQUO);
76 node["seq"].set_seq(FLOW);
77 node["seq2"].set_seq();
78 c4::yml::NodeRef child = node.append_child();
79 child.set_seq("map");
80 
81 // or now, same as above, but from the tree:
82 // more code, but also more efficient
83 tree.set_map(node_id, BLOCK);
84 c4::yml::id_type id_key = tree.append_child(node_id),
85  id_seq = tree.append_child(node_id),
86  id_seq2 = tree.append_child(node_id),
87  id_map = tree.append_child(node_id);
88 tree.set_key(id_key, "key");
89 tree.set_val(id_key, "val", VAL_SQUO);
90 tree.set_key(id_seq, "seq");
91 tree.set_seq(id_seq, FLOW);
92 tree.set_key(id_seq2, "seq2");
93 tree.set_seq(id_seq2);
94 tree.set_key(id_map, "map");
95 tree.set_map(id_map);
96 @endcode
97 
98 If you prefer to keep on using the legacy operators `=`, `|=`, `<<`, `>>`, you can enable the cmake symbol (or define the macro) `RYML_WITH_LEGACY_OPERATORS`.
99 
100 
101 <a id="notshift"></a>
102 #### Do not use operators << and >>
103 
104 For serialization, `operator<<` and `operator>>` were deprecated in favour of `.set_serialized()` and `.deserialize()` (which introduce return on error) or `.save()` and `.load()` (which trigger error callback on error):
105 @code{c++}
106 c4::yml::Tree tree = ...;
107 c4::yml::id_type node_id = ...;
108 c4::yml::NodeRef node = ...;
109 const T var1 = ...;
110 T var2 = ...;
111 
112 // before (deprecated)
113 node << var1;
114 node >> var2;
115 node << key(var1);
116 node >> key(var2);
117 
118 // now - save() and load() do checks and call error on failure
119 node.save(var1);
120 node.load(&var2);
121 node.save_key(var1);
122 node.load_key(&var2);
123 // or now, without exceptional flow: use .set_serialized() and .deserialize()
124 node.set_serialized(var1);
125 if( ! node.deserialize(&var2))
126  ...
127 node.set_key_serialized(var1);
128 if( ! node.deserialize_key(&var2))
129  ...
130 
131 // also now possible from tree!
132 tree.save(node_id, var1);
133 tree.load(node_id, &var2);
134 tree.save_key(node_id, var1);
135 tree.load_key(node_id, &var2);
136 tree.set_serialized(node_id, var1);
137 if( ! tree.deserialize(node_id, &var2))
138  ...
139 tree.set_key_serialized(node_id, var1);
140 if( ! tree.deserialize_key(node_id, &var2))
141  ...
142 @endcode
143 
144 If you prefer to keep on using the legacy operators `=`, `|=`, `<<`, `>>`, you can enable the cmake variable (or define the macro) `RYML_WITH_LEGACY_OPERATORS`.
145 
146 The rest of the changes are **optional, but recommended**. If you don't do these changes, your code will go on working as before, but the new features and improved behavior will not be available.
147 
148 
149 <a id="readresult"></a>
150 #### Optional: user-implemented `read()` should now return `ReadResult`
151 
152 Your `%read()` functions should now return a `c4::yml::ReadResult`. This enables reporting the exact node on which a deserialization error happens, even if it is nested deep in the tree, which in turn helps tremendously pinpointing troubles in YAML source (especially with location tracking):
153 @code{c++}
154 // optional: your implementation of read() should be changed from...
155 bool read(c4::yml::ConstNodeRef const& node, T *var)
156 {
157  bool success = ...;
158  return success;
159 }
160 // optional: change to this:
161 c4::yml::ReadResult read(c4::yml::ConstNodeRef const& node, T *var)
162 {
163  bool success = ...;
164  return c4::yml::ReadResult(success, node.id());
165 }
166 @endcode
167 
168 If you don't change, rapidyaml will still report the error, but on the node of the outer-most function returning false, instead of the node at the inner-most function.
169 
170 
171 <a id="treeid"></a>
172 #### Optional: user-implemented `%read()`/`%write()` should now receive `Tree` and id
173 
174 If you want to use deserialization from `Tree`, your `%read()` and `%write()` implementations should now be rewritten for `Tree`, instead of `NodeRef`. This will enable using your `%read()`/`%write()` functions **with both the `Tree` and `NodeRef` methods**:
175 
176 @code{c++}
177 // optional: your implementation of write()/read() should be changed from...
178 void write(c4::yml::NodeRef *node, T const& var)
179 {
180  ...
181 }
182 c4::yml::ReadResult read(c4::yml::ConstNodeRef const& node, T *var)
183 {
184  bool success = ...;
185  return c4::yml::ReadResult(success, node.id());
186 }
187 
188 // optional: change to this to enable serialization from/to both Tree and NodeRef:
189 void write(c4::yml::Tree* tree, c4::yml::id_type id, T const& var)
190 {
191  ...
192 }
193 c4::yml::ReadResult read(c4::yml::Tree const* tree, c4::yml::id_type id, T *var)
194 {
195  bool success = ...;
196  return c4::yml::ReadResult(success, id);
197 }
198 @endcode
199 If you don't change, you will not be able to serialize to/from `Tree`. That is, **having only the node implementation will not work with the `Tree` methods**. You can also provide both functions, and they would be picked up correctly, but that is pointless. In short, **prefer the Tree** version.
200 
201 Note also that **inside the tree version, you can still use the node API**. For example:
202 @code{c++}
203 c4::yml::ReadResult read(c4::yml::Tree const* tree, c4::yml::id_type id, T *var)
204 {
205  c4::yml::ConstNodeRef n(tree, id);
206  ... // this way you can keep the function body as before
207  // BUT read next note
208 }
209 @endcode
210 
211 
212 <a id="noloadinread"></a>
213 #### Optional: do not use `.load()` (former `>>`) inside `read()`
214 
215 Inside your `%write()/%read()` implementation **you should now use the new `.deserialize()` calls**. On error, these methods will play nice when they are called from `.deserialize()` on upper-level objects. On the contrary, `.load()` (formerly `>>`) will interrupt execution immediately, and this will prevent those upper-level calls from successfully receiving the actual [`ReadResult`](@ref c4::yml::ReadResult) and reporting it upwards.
216 
217 If you want to avoid exceptional flow and write code such as
218 @code{c++}
219 struct Inner { int foo, bar; };
220 struct Outer { Inner inner1, inner2; }
221 
222 Outer outer;
223 if( ! node.deserialize(&outer))
224  ... // we want to enter this branch without triggering an error
225 @endcode
226 ... then your `read(tree,id,Inner*)` implementation should not use `.load()`:
227 @code{c++}
228 c4::yml::ReadResult read(c4::yml::Tree const* tree, c4::yml::id_type id, Inner *inner)
229 {
230  c4::yml::ReadResult result(tree->is_map(id), id);
231  if(result) result = tree->deserialize_child(id, "foo", &inner->foo);
232  if(result) result = tree->deserialize_child(id, "bar", &inner->foo);
233  return result;
234 }
235 // Likewise for the outer type. Note how an Inner error will be
236 // transparently returned:
237 c4::yml::ReadResult read(c4::yml::Tree const* tree, c4::yml::id_type id, Outer *outer)
238 {
239  c4::yml::ReadResult result(tree->is_map(id), id);
240  if(result) result = tree->deserialize_child(id, "inner1", &outer->inner1);
241  if(result) result = tree->deserialize_child(id, "inner2", &outer->inner2);
242  return result;
243 }
244 @endcode
245 
246 In short, implementing `%read()` with `.deserialize()` plays nice with both upper `.deserialize()` and `.load()` calls, whereas implementing `%read()` with `.load()` will only work with upper `.load()` calls.
247 
248 
249 <a id="deserializechild"></a>
250 #### Recommended: use new methods `.deserialize_child()` in `read()`
251 
252 Inside your `read()` implementation, **you should now use the new methods `.deserialize_child()`**.
253 
254 This release also adds a family of tree and node methods returning `c4::yml::ReadResult` to simplify `%read()` implementations. Each of these returns a `ReadResult` object that is ready to return on error. Consider the following node-based `%read()`, already using `.deserialize()`:
255 @code{c++}
256 ryml::ReadResult read(ryml::ConstNodeRef const& n, my_type *val)
257 {
258  ryml::ReadResult r(n.is_map(), n.id());
259  if(r) r = n["v2"].deserialize(&val->v2); // don't. using [] will throw error if "v2" is not a child
260  if(r) r = n["v3"].deserialize(&val->v3);
261  if(r) r = n["v4"].deserialize(&val->v4);
262  if(r) r = n["seq"].deserialize(&val->seq);
263  if(r) r = n["map"].deserialize(&val->map);
264  return r;
265 }
266 @endcode
267 Note that any of the `operator[]` calls (or more precisely the `.deserialize()` calls on its result) may trigger a visit error when no such node exists. To avoid exceptional flow in case of error, you should now use `.deserialize_child()`. The function below will gracefully return an appropriate error status when any of the child nodes does not exist:
268 @code{c++}
269 ryml::ReadResult read(ryml::ConstNodeRef const& n, my_type *val)
270 {
271  ryml::ReadResult r(n.is_map(), n.id());
272  if(r) r = n.deserialize_child(n, "v2", &val->v2); // there is also a fall-back overload
273  // receiving a default value when
274  // no such child exists
275  if(r) r = n.deserialize_child(n, "v3", &val->v3);
276  if(r) r = n.deserialize_child(n, "v4", &val->v4);
277  if(r) r = n.deserialize_child(n, "seq", &val->seq);
278  if(r) r = n.deserialize_child(n, "map", &val->map);
279  return r;
280 }
281 @endcode
282 Here's the list of new `ReadResult`-returning methods that may be of use in similar scenarios:
283  - `.deserialize_child()`: [Tree](@ref c4::yml::Tree::deserialize_child()), [ConstNodeRef](@ref c4::yml::ConstNodeRef::deserialize_child()), [NodeRef](@ref c4::yml::NodeRef::deserialize_child())
284  - `.child_r()`: [Tree](@ref c4::yml::Tree::child_r()), [ConstNodeRef](@ref c4::yml::ConstNodeRef::child_r()), [NodeRef](@ref c4::yml::NodeRef::child_r())
285  - `.find_child_r()`: [Tree](@ref c4::yml::Tree::find_child_r()), [ConstNodeRef](@ref c4::yml::ConstNodeRef::find_child_r()), [NodeRef](@ref c4::yml::NodeRef::find_child_r())
286  - likewise for sibling: added `sibling_r` and `find_sibling_r()`
287  - The `.get_if()` methods were deprecated in favour of `.deserialize_child()`.
288 
289 
290 <a id="v016changelogsection"></a>
291 ### Full changelog
292 
293 - Update c4core to [v0.6.0](https://github.com/biojppm/c4core/releases/tag/v0.6.0)
294 - [PR#649](https://github.com/biojppm/rapidyaml/pull/649) commit to ABI stability on patch releases before 0.x, then on minor releases after 1.x
295 - [PR#648](https://github.com/biojppm/rapidyaml/pull/648) improve documentation, add benchmark results
296 - [PR#647](https://github.com/biojppm/rapidyaml/pull/647) remove support for UTF16 and UTF32 encoded files
297 - [PR#646](https://github.com/biojppm/rapidyaml/pull/646) improve Doxygen docs, update yamlscript version
298 - [PR#645](https://github.com/biojppm/rapidyaml/pull/645) tools: unify ryml-parse-emit and ryml-yaml-events, remove ryml-yaml-events
299 - [PR#644](https://github.com/biojppm/rapidyaml/pull/644) amalgamate: add `--fastfloat_sys` to use fastfloat from system
300 - [PR#643](https://github.com/biojppm/rapidyaml/pull/643) reduce source archive size: move large data files used in benchmarks to [rapidyaml-data](https://github.com/biojppm/rapidyaml-data) repo.
301 - [PR#642](https://github.com/biojppm/rapidyaml/pull/642) amalgamate: add option to create single source+header.
302 - [PR#641](https://github.com/biojppm/rapidyaml/pull/641): change uses of `C4_LIKELY()` / `C4_UNLIKELY()` to turn into `[[likely]]` / `[[unlikely]]`. No logic changes.
303 - [PR#640](https://github.com/biojppm/rapidyaml/pull/640): add `.deserialize_child()` methods to simplify `%read()` implementations
304 - [PR#639](https://github.com/biojppm/rapidyaml/pull/639): fix names using leading/double underscore (renames only, no logic changes).
305 - [PR#638](https://github.com/biojppm/rapidyaml/pull/638): improve quickstart-ints.
306 - [PR#637](https://github.com/biojppm/rapidyaml/pull/637): add cmake option `RYML_SYSTEM_C4CORE` to consume c4core from `find_package()`. Thanks \@uilianries!
307 - [PR#636](https://github.com/biojppm/rapidyaml/pull/636) **remove c4core submodule**, and copy c4core files to rapidyaml (and manage sync):
308  - `ext/c4core.src/`: c4core code used in the rapidyaml library
309  - `ext/c4core.dev/`: c4core code used by tests/benchmarks
310  - `proj/`: project files like cmake files and toolchains
311  - `RYML_STANDALONE` can still be set to `OFF` to compile against an out-of-source c4core (see also the newly added `RYML_SYSTEM_C4CORE`)
312  - the amalgamation tool now adds only the files in `c4core.src` files, and has new option `--c4core-dev` to include the `c4core.dev` files
313  - adds (internal) tools to manage c4core synchronization scenarios. See [ext/README.md](https://github.com/biojppm/rapidyaml/tree/master/ext) for details with this.
314 - [PR#635](https://github.com/biojppm/rapidyaml/pull/635) API cleanup: `NodeType` and `extra::ievt::EventFlags`:
315  - On `Tree` and `NodeRef`, overloads taking `NodeType_e` are now receiving `type_bits`.
316  - This saves operator calls on type queries.
317  - Remove bitwise operators, no longer needed.
318  - Rename `NodeType_e` to `NodeTypeBits` (deprecate `NodeType_e`)
319  - Low impact, no changes should be needed on user code, other than renaming unlikely uses of `NodeType_e`.
320  - Also, for int events: rename `extra::ievt::EventFlags` to `extra::ievt::EventBits`
321 - [PR#620](https://github.com/biojppm/rapidyaml/pull/620) API cleanup: `Tree` and `NodeRef`:
322  - Deprecate `NodeInit`
323  - `Tree` and `NodeRef`:
324  - deprecate `.to_val()` and friends -- add `.set_val()` and friends.
325  - deprecate `operator=(csubstr)` and friends -- use `.set_val()` instead.
326  - deprecate `operator|=(NodeType)` and `operator=(NodeType)` -- use appropriate overload `.set_*(T, NodeType)`.
327  - You can disable compiler deprecation warnings from use of these operators: by enabling the cmake variable (or defining the macro) `RYML_WITH_LEGACY_OPERATORS`.
328  - deprecate `NodeInit` and `NodeScalar` methods in `Tree` and `NodeRef` (use `.set_*()`)
329  - deprecate single-arg `NodeRef::{duplicate,move}(ConstNodeRef)`
330  - deprecate `NodeRef::visit()` and `NodeRef::visit_stacked()`
331  - add `Tree::arena_rem()`
332  - add `RYML_DEFAULT_TREE_ARENA_CAPACITY_START` with default value of 256
333  - `parse_*()`: internal simplification, no semantic changes
334 - [PR#589](https://github.com/biojppm/rapidyaml/pull/589) API cleanup: serialization and tree building
335  - Refactor serialization code:
336  - Deprecate `operator<<`, use `.load()` / `.load_key()` or `.deserialize()` / `.deserialize_key()`
337  - Deprecate `operator>>`, use `.save()` / `.save_key()` or `.set_serialized()` / `.set_key_serialized()`
338  - Deprecate `key()` tag function and `Key` tag type (needed only for the operators above)
339  - Migration of code triggering serialization:
340  - If you don't want to migrate yet, use `RYML_WITH_LEGACY_OPERATORS` to disable compiler deprecation warnings from use of these operators.
341  - Serialization with `Tree` API is now fully implemented, working exactly the same as `NodeRef`
342  - serialization:
343  - `NodeRef` serialized with `%write(NodeRef *, T const&)` and `%write_key()`
344  - `Tree` serialized with `%write(Tree *, id_type, T const&)` and `%write_key()`
345  - No changes in types using `%to_chars()` serialization
346  - deserialization:
347  - `ConstNodeRef` deserialized with `%read(ConstNodeRef const&, T *)` and `%read_key()`
348  - `Tree` deserialized with `%read(Tree const*, id_type, T *)` and `%read_key()` (removed old `%readkey()` approach.)
349  - No changes in types using `%from_chars()` serialization
350  - Enables bypass of `NodeRef` serialization to use the tree API, which is faster to compile.
351  - Organize serialization in layers, ensuring use of free functions to enable the user to override at all levels with ADL, for total control of type behavior (explained in the doxygen documentation).
352  - Added many more unit tests to ensure all scenarios are working.
353  - Move scalar specific code to new top-level headers `c4/yml/scalar_charconv.hpp` and `c4/yml/scalar_style.hpp`
354  - Relax deserialization of nodes with `VALNIL` or `KEYNIL`, such that non-fundamental types can now be null-initialized (eg initialize a string from a null scalar). Fundamental types such as ints or floats will still report an error.
355  @code{c++}
356  Tree tree = parse_in_arena("{empty: }");
357  std::string str;
358  tree["empty"].load(&str); // relaxed: no longer a deserialization error
359  assert(s.empty());
360  int val;
361  tree["empty"].load(&val); // ERROR! as before.
362  @endcode
363 - [PR#626](https://github.com/biojppm/rapidyaml/pull/626): ensure accurate reporting of nodes causing deeply nested serialization error. This enables reporting the inner-most node causing the error! To profit from this, `%read()` user functions should now return `ReadResult` instead of `bool`. This change is backwards-compatible with legacy `%read()` functions returning `bool`, but the legacy version will remain less precise: it will report an inner error on the upmost node returning false, possibly the root if all levels are returning bool. See the new `sample_deserialize_error()` on the quickstart, and the [latest doxygen documentation](https://rapidyaml.readthedocs.io/latest/doxygen/group__doc__serialization__user__types.html). The user functions should change (but not mandatory):
364  @code{c++}
365  // before
366  bool read(ryml::ConstNodeRef n, T *var) { ... }
367  // now (should be changed, but not mandatory)
368  ryml::ReadResult read(ryml::ConstNodeRef n, T *var) { ... }
369  @endcode
370 - [PR#625](https://github.com/biojppm/rapidyaml/pull/625): Set plain scalar style when serializing arithmetic scalars: improves emit speed of numeric-heavy data payloads.
371 - [PR#616](https://github.com/biojppm/rapidyaml/pull/616) API cleanup: emit
372  - `WriterFile` and `WriterOStream` no longer track the number of emitted bytes.
373  - `error_on_excess` is now used in the emit-to-buffer overloads, and no longer in the main `Emitter::emit_as()` driver function.
374 - [PR#617](https://github.com/biojppm/rapidyaml/pull/617) API cleanup: emit, part 2
375  - Tidy emit classes among new top-level header files:
376  - `c4/yml/emit_container.hpp`: emit to resizeable contiguous char container (eg `std::string`, `std::vector<char>`)
377  - `c4/yml/emit_buf.hpp`: emit to char buffer (`substr`)
378  - `c4/yml/emit_file.hpp`: emit to C `FILE*`
379  - `c4/yml/emit_ostream.hpp`: emit to STL-like ostreams
380  - The old `c4/yml/emit.hpp` is now a pure umbrella header, including all of the above. For better compilation speed, avoid the umbrella header, and prefer including the concrete header (container, buf, file or stream).
381  - The rest of the emit code was split over these new implementation headers:
382  - `c4/yml/emit_options.hpp`: options to control emitting
383  - `c4/yml/emitter.hpp`: main emitter class
384  - `c4/yml/emitter.def.hpp`: definitions of main emitter class.
385  - `c4/yml/writer_buf.hpp`: policy class to emit to char buffer (`substr`)
386  - `c4/yml/writer_file.hpp`: policy class to emit to C `FILE*`
387  - `c4/yml/writer_ostream.hpp`: policy class to emit to STL-like ostreams
388  - There are no semantic changes: all the `emit_*()` functions remain the same.
389  - Other changes in this PR:
390  - Added `Tree::root_id_maybe()` which is safe to call on an empty tree.
391  - Deprecate `Emitter::max_depth()`
392  - Deprecate `Emitter::options()` setter
393 - [PR#618](https://github.com/biojppm/rapidyaml/pull/618): API cleanup: emit, part 3
394  - Improve handling of `NaN` and `Inf` in json emitting.
395  - Expose scalar style helpers for json emitting:
396  @code{c++}
397  bool scalar_is_plain_number_json();
398  bool scalar_is_special_json();
399  bool scalar_is_inf3();
400  bool scalar_is_nan3();
401  bool scalar_is_inf_or_nan3();
402  @endcode
403  - Writers: add `C4_ALWAYS_INLINE`. Results in ~10-20% emit improvements.
404  - `file_put_contents()`: add `FILE*` overloads
405 - [PR#621](https://github.com/biojppm/rapidyaml/pull/621) API cleanup: `NodeRef`:
406  - Simplify internal implementation of `{Const}NodeRef::{iterator,children_view}`.
407  - Stop using SFINAE on Node CRTP to distinguish const vs non const, by duplicating the functions in `NodeRef` vs `ConstNodeRef`. No semantic changes. This should improve compilation speed of code containing many node calls.
408 - [PR#622](https://github.com/biojppm/rapidyaml/pull/622) API cleanup: remove preprocess utilities.
409 - [PR#623](https://github.com/biojppm/rapidyaml/pull/623): YAML fuzzing fixes, and close to 1 billion fuzz runs without any errors. These were the only two problems found:
410  - Ensure parse error on multiline keys opening YAML:
411  @code{yaml}
412  multiline
413  key: value
414  @endcode
415  - Fix parse error on Byte Order Mark opening containers:
416  @code{yaml}
417  <BOM>-
418  - a
419  -
420  @endcode
421 - [PR#628](https://github.com/biojppm/rapidyaml/pull/628): Add serialization fuzzing. Relax `c4::atof()` / `c4::atod()`, disable redundant assertions that prevent returning false on bad strings.
422 - [PR#629](https://github.com/biojppm/rapidyaml/pull/629): int events:
423  - Rename `to_chars(substr,DataType)` to `to_str()` (the existing c4 overload would always win because it's an int)
424  - Do not use c4/bitmask.hpp
425 - [PR#633](https://github.com/biojppm/rapidyaml/pull/633): improve coverage to ~99.5%:
426  - Add tests to cover missed lines
427  - Change some errors to assertions; those errors are caught before calling.
428  - `Tree` and `NodeRef`: deprecate `.type_str()`. Use `.type().type_str()`
429  - Tools: add ints parsing to ryml-emit-parse
430 - [PR#634](https://github.com/biojppm/rapidyaml/pull/634): int events: add sample containing ints-only library
431 - [PR#590](https://github.com/biojppm/rapidyaml/pull/590): minor: prefer calling some predicates from `NodeType`
432 
433 
434 ### Thanks
435 
436 - \@uilianries
437 
438 
439 ----------------------------
440 <a name="v0.15.2"></a>
441 ## 0.15.2
442 
443 [Github release: 0.15.2](https://github.com/biojppm/rapidyaml/releases/tag/v0.15.2)
444 
445 - Workaround for Doxygen changelog (use of HTML anchors in .md: doxy 1.15 fails but 1.16 succeeds).
446 
447 
448 ----------------------------
449 <a name="v0.15.1"></a>
450 ## 0.15.1
451 
452 [Github release: 0.15.1](https://github.com/biojppm/rapidyaml/releases/tag/v0.15.1)
453 
454 - [PR#618](https://github.com/biojppm/rapidyaml/pull/618):
455  - JSON emitter now adheres to flow style customization from [PR#615](https://github.com/biojppm/rapidyaml/pull/615)
456  - JSON emitter now tolerates YAML streams (ie a seq of docs), and emits these as a top-level seq. The old behavior of throwing an error on streams can be obtained by using the new option [EmitOptions::json_err_on_stream()](@ref c4::yml::EmitOptions::json_err_on_stream()).
457  - Fix error in [EmitOptions](@ref c4::yml::EmitOptions) where [EmitOptions::emit_nonroot_dash()](@ref c4::yml::EmitOptions::emit_nonroot_dash()) had the same effect as [EmitOptions::json_err_on_tag()](@ref c4::yml::EmitOptions::json_err_on_tag()).
458 
459 
460 ----------------------------
461 <a name="v0.15.0"></a>
462 ## 0.15.0
463 
464 [Github release: 0.15.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.15.0)
465 
466 - [PR#615](https://github.com/biojppm/rapidyaml/pull/615): add flow style customization:
467  - Add [FLOW_SPC](@ref c4::yml::FLOW_SPC) to force space after comma in flow style containers:
468  @code{c++}
469  c4::yml::Tree tree = c4::yml::parse_in_arena("[0,1,2,3,4,5,6]");
470  CHECK(c4::yml::emitrs_yaml<std::string>(tree), "[0,1,2,3,4,5,6]");
471  // add spaces:
472  tree.rootref().set_container_style(c4::yml::FLOW_SL|c4::yml::FLOW_SPC);
473  CHECK(c4::yml::emitrs_yaml<std::string>(tree), "[0, 1, 2, 3, 4, 5, 6]");
474  @endcode
475  - Add [FLOW_MLN](@ref c4::yml::FLOW_MLN) (flow multiline, multi-values per line, wrapped at max columns). The old `FLOW_ML` was deprecated, and is now known as [FLOW_ML1](@ref c4::yml::FLOW_ML1) (flow multiline, 1 value per line):
476  @code{c++}
477  tree.rootref().set_container_style(c4::yml::FLOW_ML1);
478  CHECK(c4::yml::emitrs_yaml<std::string>(tree),
479  "[\n"
480  " 0,\n"
481  " 1,\n"
482  " 2,\n"
483  " 3,\n"
484  " 4,\n"
485  " 5,\n"
486  " 6\n"
487  "]\n");
488  tree.rootref().set_container_style(c4::yml::FLOW_MLN);
489  CHECK(c4::yml::emitrs_yaml<std::string>(tree),
490  "[\n"
491  " 0,1,2,3,4,5,6\n"
492  "]\n");
493  @endcode
494  - Add [FLOW_MLX](@ref c4::yml::FLOW_MLX) mask to match both [FLOW_ML1](@ref c4::yml::FLOW_ML1) and [FLOW_MLN](@ref c4::yml::FLOW_MLN)
495  - Add [EmitOptions::max_cols()](@ref c4::yml::EmitOptions::max_cols()) to control wrapping of [FLOW_MLN](@ref c4::yml::FLOW_MLN):
496  @code{c++}
497  auto maxcols8 = c4::yml::EmitOptions{}.max_cols(8);
498  CHECK(c4::yml::emitrs_yaml<std::string>(tree, maxcols8),
499  "[\n"
500  " 0,1,2,\n"
501  " 3,4,5,\n"
502  " 6\n"
503  "]\n");
504  @endcode
505  - Add [EmitOptions::force_flow_spc()](@ref c4::yml::EmitOptions::force_flow_spc()) to override all per-node settings of [FLOW_SPC](@ref c4::yml::FLOW_SPC) when emitting:
506  @code{c++}
507  auto force_spaces = c4::yml::EmitOptions{}.force_flow_spc(true);
508  CHECK(c4::yml::emitrs_yaml<std::string>(tree, force_spaces),
509  "[\n"
510  " 0, 1, 2, 3, 4, 5, 6\n"
511  "]\n");
512  @endcode
513  - Add [ParserOptions::flow_ml_style()](@ref c4::yml::ParserOptions::flow_ml_style()) to choose the multiline flow style to assign while parsing. The default value is still [FLOW_ML1](@ref c4::yml::FLOW_ML1) (the old behavior), but this option allows picking any of [FLOW_MLN](@ref c4::yml::FLOW_MLN) or [FLOW_ML1](@ref c4::yml::FLOW_ML1).
514  - See [sample_style_flow_formatting()](@ref sample_style_flow_formatting()) in the quickstart for more info.
515 
516 
517 ----------------------------
518 <a name="v0.14.0"></a>
519 ## 0.14.0
520 
521 [Github release: 0.14.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.14.0)
522 
523 - [PR#607](https://github.com/biojppm/rapidyaml/pull/607): add file utilities:
524  - [file_put_contents()](@ref c4::yml::file_put_contents())
525  - [file_get_contents()](@ref c4::yml::file_get_contents())
526  - [stdin_get_contents()](@ref c4::yml::stdin_get_contents())
527 - [PR#609](https://github.com/biojppm/rapidyaml/pull/609): fix misbuild in gcc 16.
528 - [PR#610](https://github.com/biojppm/rapidyaml/pull/610): fix clang warnings: `-Weverything`. Thanks [\@TedLyngmo](https://github.com/TedLyngmo)!
529 - [PR#613](https://github.com/biojppm/rapidyaml/pull/613): fix [#612](https://github.com/biojppm/rapidyaml/pull/612): parse error on whitespace-only after block scalar indicators `|` or `>`:
530  @code{yaml}
531  space after: >\space
532  tag after: >\t
533  @endcode
534 - [PR#614](https://github.com/biojppm/rapidyaml/pull/614) improve base64 serialization facilities:
535  @code{c++}
536  std::string decoded;
537  tree["node"] >> fmt::base64(decoded); // now possible
538  // also can now obtain the size explicitly:
539  substr buf = ...;
540  size_t required = 0;
541  tree["node"] >> fmt::base64(buf, &required);
542  @endcode
543 - Update c4core to [0.4.0](https://github.com/biojppm/c4core/releases/tag/v0.4.0).
544 
545 
546 ### Thanks
547 
548 - [\@TedLyngmo](https://github.com/TedLyngmo)
549 
550 
551 ----------------------------
552 <a name="v0.13.0"></a>
553 ## 0.13.0
554 
555 [Github release: 0.13.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.13.0)
556 
557 - [PR#606](https://github.com/biojppm/rapidyaml/pull/606): scalar style utilities now are specific to flow/block mode. This enables stable-style roundtrips of block-mode plain scalars with characters invalid in flow mode:
558  @code{yaml}
559  # these scalars were previously emitted as single-quoted style
560  # because they were conservatively assumed to be in flow mode.
561  - doe: a deer, a female deer
562  - (10,11)
563  - also scalars containing [] and {}
564  @endcode
565  - `scalar_style_choose()` was split into [scalar_style_choose_flow()](@ref c4::yml::scalar_style_choose_flow()) and [scalar_style_choose_block()](@ref c4::yml::scalar_style_choose_block())
566  - `scalar_style_query_plain()` was split into [scalar_style_query_plain_flow()](@ref c4::yml::scalar_style_query_plain_flow()) and [scalar_style_query_plain_block()](@ref c4::yml::scalar_style_query_plain_block())
567  - [NodeType::type_str_sub()](@ref c4::yml::NodeType::type_str()): remove zero-termination, use common approach of returning required size
568  - Add [NodeType::type_str_sub()](@ref c4::yml::NodeType::type_str_sub())
569 - [PR#605](https://github.com/biojppm/rapidyaml/pull/605): fix parse errors:
570  - `:` and `#` on continuation lines of multiline plain scalars:
571  @code{yaml}
572  [plain
573  :scalar] # leading colon belongs to the scalar
574  @endcode
575  - Tabs inside quoted scalars opening a map were mistook for indentation tabs:
576  @code{yaml}
577  foo:
578  '\ta': b
579  @endcode
580 - [PR#604](https://github.com/biojppm/rapidyaml/pull/604): add string_view and span to the @ref c4/yml/std/std.hpp interop umbrella header.
581 - Fix [600](https://github.com/biojppm/rapidyaml/issues/600): shared symbols not exported in clang on Windows ([PR#601](https://github.com/biojppm/rapidyaml/pull/601)).
582 - Fix [256](https://github.com/biojppm/rapidyaml/issues/256): installation directory on Linux 64bit ([PR#599](https://github.com/biojppm/rapidyaml/pull/599)). See also original fix at [cmake#16](https://github.com/biojppm/cmake/pull/16). Big thanks to [\@GabrielBarrantes](https://github.com/GabrielBarrantes) and [\@musicinmybrain](https://github.com/musicinmybrain), not just for their fixes but also for all their downstream work!
583 - [PR#591](https://github.com/biojppm/rapidyaml/pull/591): Add missing includes to avoid compilation warning. Thanks [\@GabrielBarrantes](https://github.com/GabrielBarrantes)!
584 - Update c4core to [0.3.0](https://github.com/biojppm/c4core/releases/tag/v0.3.0)
585 
586 
587 ### Thanks
588 
589  - [\@GabrielBarrantes](https://github.com/GabrielBarrantes)
590  - [\@musicinmybrain](https://github.com/musicinmybrain)
591 
592 
593 ----------------------------
594 <a name="v0.12.1"></a>
595 ## 0.12.1
596 
597 [Github release: 0.12.1](https://github.com/biojppm/rapidyaml/releases/tag/v0.12.1)
598 
599 - Fix [#597](https://github.com/biojppm/rapidyaml/pull/597): parse error when quoted scalars start with `...` or `---` ([PR#598](https://github.com/biojppm/rapidyaml/pull/598)). This fixes a regression introduced in ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)), while trying to ensure a parse error when `...` or `---` occur in quoted scalars at a line begin.
600 
601 
602 ----------------------------
603 <a name="v0.12.0"></a>
604 ## 0.12.0
605 
606 [Github release: 0.12.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.12.0)
607 
608 This release focuses in compliance with the YAML standard, mostly by ensuring parse errors in invalid YAML cases. rapidyaml **is now 100% compliant to the YAML test suite, both for valid and invalid YAML cases**.
609 
610 ### General fixes and improvements
611 
612 - Narrow the scope of `%TAG` to only the following document, as per the standard ([PR#588](https://github.com/biojppm/rapidyaml/pull/588)). This required or prompted some API changes:
613  - Added new type [TagDirectives](@ref c4::yml::TagDirectives)
614  - Added [ParserOptions::resolve_tags()](@ref c4::yml::ParserOptions::resolve_tags()) and [ParserOptions::resolve_tags_all()](@ref c4::yml::ParserOptions::resolve_tags_all()) options to allow controling resolution of tags while parsing. When disabled (which is the default), the tree still has `Tree::resolve_tags()` to perform post-parsing or programmatic resolution.
615  - Changed [TagDirective](@ref c4::yml::TagDirective) to point at its in-scope document, changed API to reflect this.
616  - [ParseEngine](@ref c4::yml::ParseEngine) now has an instance of [TagDirectives](@ref c4::yml::TagDirectives), and is in charge of updating it and checking for directive errors.
617  - Removed the old `TagDirective m_tag_directives[]` members from the ints and testsuite handlers. [Tree](@ref c4::yml::Tree) also has its own [TagDirectives](@ref c4::yml::TagDirectives) member, redundantly updated during parsing: this enables programmatic manipulation the tree's tag directives .
618  - The event handlers now track the current document id, in order to enable the document scope check for `%TAG` directives. This required adding node id tracking to the ints and testsuite handlers.
619  - Added [Tree::ancestor_doc(node_id)](@ref c4::yml::Tree::ancestor_doc()) and [ConstNodeRef::ancestor_doc()](@ref c4::yml::ConstNodeRef::ancestor_doc()) to query for the parent document of a node. This is needed to implement resolution of tags.
620  - [NodeType](@ref c4::yml::NodeType): rename tag directive types `TAGD`->`TAGH` (tag handle) and `TAGV`->`TAGP` (tag prefix).
621  - Internal changes to improve the design of event handlers, moving relocation and error checking logic to [ParseEngine](@ref c4::yml::ParseEngine), where it is most suited.
622  - Fix warnings with clang-tidy 22
623 - [PR#596](https://github.com/biojppm/rapidyaml/pull/596): Add [TagCache](@ref c4::yml::TagCache) accelerator structure (in `c4/yml/tag.hpp`), used by [Tree::resolve_tags()](@ref c4::yml::Tree::resolve_tags()) and the parser engine. This reduces significantly the arena requirements for heavily-tagged YAML by ensuring reuse of resolved tags.
624 
625 
626 ### YAML fixes: valid cases
627 
628 Fix parsing of **valid** YAML corner cases:
629  - Ambiguity of tags/anchors in ? mode ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
630  @code{yaml}
631  ? &mapanchor
632  key: val
633  ?
634  &keyanchor key: val
635  @endcode
636  - flow tags/anchors with omitted plain scalar ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
637  @code{yaml}
638  # ... likewise for !tag
639  - [&anchor,&anchor]
640  - {&anchor,&anchor}
641  - [&anchor :,&anchor :]
642  - {&anchor :,&anchor :}
643  - [: &anchor,: &anchor]
644  - {: &anchor,: &anchor}
645  ---
646  ? anchor
647  @endcode
648  - flow tags/anchors terminating with `:` (the colon is part of the tag/anchor) ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
649  @code{yaml}
650  # ... likewise for !tag:
651  - [&anchor:,&anchor:]
652  - {&anchor:,&anchor:}
653  - [&anchor: :,&anchor: :]
654  - {&anchor: :,&anchor: :}
655  - [: &anchor:,: &anchor:]
656  - {: &anchor:,: &anchor:}
657  ---
658  ? anchor
659  @endcode
660  - Fix corner cases of explicit keys now allow same-line containers ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
661  @code{yaml}
662  ? - a # same-line container key now parses successfully. both seqs and maps
663  : - b # same-line container val now parses successfully. both seqs and maps
664  ? ? - c # nested explicit keys were also fixed
665  ? - d
666  @endcode
667  - Missing tags/anchors in some flow maps ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)).
668 
669 
670 ### YAML fixes: invalid cases
671 
672 Ensure parse errors for **invalid** YAML cases, and improve reported error location:
673  - `%TAG` directives are valid only in the following document ([PR#588](https://github.com/biojppm/rapidyaml/pull/588)).
674  @code{yaml}
675  %TAG !m my-
676  --- !m!first a
677  --- !m!second a # error: %TAG directive out of scope here
678  ...
679  %TAG !m your-
680  --- !m!second a # ok: %TAG provided now.
681  @endcode
682  - colon on newline at top level ([PR#585](https://github.com/biojppm/rapidyaml/pull/585)):
683  @code{yaml}
684  scalar
685  : bad
686  ---
687  [seq]
688  : bad
689  ---
690  {map: }
691  : bad
692  @endcode
693  - colon on newline generally in block containers ([PR#585](https://github.com/biojppm/rapidyaml/pull/585)):
694  @code{yaml}
695  bad cases:
696  scalar
697  : bad colon
698  [seq]
699  : bad colon
700  {map: }
701  : bad colon
702  @endcode
703  - colon on newline in flow sequences ([PR#586](https://github.com/biojppm/rapidyaml/pull/586)):
704  @code{yaml}
705  [a
706  :
707  b]
708  @endcode
709  - tokens after explicit document end ([PR#585](https://github.com/biojppm/rapidyaml/pull/585)):
710  @code{yaml}
711  foo: bar
712  ... bad tokens
713  @endcode
714  - `-` is invalid scalar in flow sequences ([PR#586](https://github.com/biojppm/rapidyaml/pull/586)):
715  @code{yaml}
716  [-]
717  ---
718  [-,-]
719  ---
720  [--,-]
721  ---
722  [-
723  ]
724  @endcode
725  - doc start/begin tokens at zero indentation in seq flow and quoted scalars ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
726  @code{yaml}
727  [
728  ---,
729  --- ,
730  ...,
731  ... ,
732  # etc
733  ]
734  ---
735  "
736  --- # error as well
737  ... # error as well
738  "
739  ---
740  '
741  --- # error as well
742  ... # error as well
743  '
744  @endcode
745  - nested flow containers now enforce the contextual parent indentation ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
746  @code{yaml}
747  - - - [
748  a # now this is a parse error
749  ]
750  - - - [
751  a # this is ok
752  ]
753  @endcode
754  - single/double-quoted scalars now enforce the contextual parent indentation ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
755  @code{yaml}
756  - - - "a
757  b" # now this is a parse error
758  - - - "a
759  b" # this is ok
760  @endcode
761  - plain scalars in block mode starting with `,` ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
762  @code{yaml}
763  all invalid:
764  - , foo
765  - ,foo
766  - ,
767  @endcode
768  - references with anchors or tags ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
769  @code{yaml}
770  all invalid:
771  - &anchor *ref
772  - !tag *ref
773  @endcode
774  - directives with extra tokens ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
775  @code{yaml}
776  %YAML 1.2 blabla # invalid
777  %YAML 1. # this is ok
778  %TAG ! my- ! blabla # this is also wrong
779  ---
780  @endcode
781  - multiline implicit keys are invalid ([PR#587](https://github.com/biojppm/rapidyaml/pull/587)):
782  @code{yaml}
783  multiline
784  plain: invalid
785  'multiline
786  squoted': invalid
787  "multiline
788  dquoted": invalid
789  [multiline,
790  seq]: invalid
791  {multiline:
792  map}: invalid
793  @endcode
794  - invalid block containers after document open ([PR#592](https://github.com/biojppm/rapidyaml/pull/592)):
795  @code{yaml}
796  --- a: b # invalid
797  --- - a # invalid
798  --- ? a # invalid
799  @endcode
800  - invalid block containers after in-block open ([PR#592](https://github.com/biojppm/rapidyaml/pull/592)):
801  @code{yaml}
802  a: - b # invalid
803  a: ? b # invalid
804  @endcode
805  - same-line repeated annotations ([PR#592](https://github.com/biojppm/rapidyaml/pull/592)):
806  @code{yaml}
807  !a
808  !b foo: bar # ok
809  ---
810  &a
811  &b foo: bar # ok
812  ---
813  !a !b foo: bar # invalid
814  ---
815  &a &b foo: bar # invalid
816  @endcode
817  - Fix parsing of invalid YAML: block scalars with deindented first line ([PR#593](https://github.com/biojppm/rapidyaml/pull/593)):
818  @code{yaml}
819  # the _ characters are not part of the YAML;
820  # they are used here only to show the leading whitespace
821  empty block scalar: >
822  _
823  _
824  _
825  # comment
826  @endcode
827 
828 
829 
830 ----------------------------
831 <a name="v0.11.1"></a>
832 ## 0.11.1
833 
834 [Github release: 0.11.1](https://github.com/biojppm/rapidyaml/releases/tag/v0.11.1)
835 
836 - [PR#583](https://github.com/biojppm/rapidyaml/pull/583): Fix corner cases of container keys. Eg, parsing of [explicit keys forming valid YAML](https://play.yaml.com/?show=xd#PwogID8gICMgd2FzIGNhdXNpbmcgYSBwYXJzZSBlcnJvcgo/ICAgICMgcG9wcGluZyB3YXMgYWxzbyBjYXVzaW5nIGEgcGFyc2UgZXJyb3IKLS0tCj8gW2E6IGJdOiB4CjogeQo=) like:
837  @code{yaml}
838  ?
839  ? # was causing a parse error
840  ? # popping was also causing a parse error
841  ---
842  ? [a: b]: x
843  : y
844  @endcode
845  With this fix, **rapidyaml now has a 100% success rate for valid YAML cases** in the YAML test suite.
846 - [PR#580](https://github.com/biojppm/rapidyaml/pull/580): fix compilation error when `RYML_NO_DEFAULT_CALLBACKS` is defined (thanks [\@toge](https://github.com/toge))
847 - [PR#582](https://github.com/biojppm/rapidyaml/pull/582): fix compilation error with clang-cl
848 - Fix [#584](https://github.com/biojppm/rapidyaml/pull/584): install: `RYML_VERSION` was missing from rymlConfig.cmake
849 - Update c4core to [0.2.11](https://github.com/biojppm/c4core/releases/tag/v0.2.11)
850 
851 
852 ### Python
853 
854 - [PR#579](https://github.com/biojppm/rapidyaml/pull/579): python packaging files and CI infrastructure was moved to a different repo [biojppm/rapidyaml-python](https://github.com/biojppm/rapidyaml-python). This was done because python packaging is notoriously hard and has always posed trouble in the CI, standing in the way of C++ development and releases.
855 
856 
857 ### Thanks
858 
859 - [\@toge](https://github.com/toge)
860 
861 
862 ----------------------------
863 <a name="v0.11.0"></a>
864 ## 0.11.0
865 
866 [Github release: 0.11.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.11.0)
867 
868 ### New features
869 
870 - [PR#550](https://github.com/biojppm/rapidyaml/pull/550) - Implement flow multiline style ([FLOW_ML](@ref c4::yml::FLOW_ML1)):
871  - The parser now detects this style automatically for flow seqs or maps when the terminating bracket sits on a line different from the opening bracket.
872  - Added [ParserOptions::detect_flow_ml()](@ref c4::yml::ParserOptions::detect_flow_ml()) to enable/disable this behavior
873  - Added [EmitOptions::indent_flow_ml()](@ref c4::yml::EmitOptions::indent_flow_ml()) to control indentation of [FLOW_ML](@ref c4::yml::FLOW_ML1) containers
874  - The emit implementation was refactored, and is now significantly cleaner
875  - Emitted YAML will now have anchors emitted before tags, as is customary ([see example](https://play.yaml.com/main/parser?input=LSAhdGFnICZhbmNob3IgfAogIG5vdGUgaG93IHRoZSBhbmNob3IgY29tZXMKICBmaXJzdCBpbiB0aGUgZXZlbnRz)).
876  - Added [ParserOptions](@ref c4::yml::ParserOptions) defaulted argument to temp-parser overloads of `parse_{yaml,json}_in_{place,arena}()`
877  - [PR#567](https://github.com/biojppm/rapidyaml/pull/567) (fixes [#566](https://github.com/biojppm/rapidyaml/issues/566)) fixes a regression from this refactor where top-level container anchors were wrongly emitted in the same line if no style was set on the container.
878 
879 
880 ### API changes
881 
882 - **BREAKING** [PR#503](https://github.com/biojppm/rapidyaml/pull/503) (fixes [#399](https://github.com/biojppm/rapidyaml/issues/399)): change error callbacks.
883  - Errors in ryml now have one of these types:
884  - parse error: when parsing YAML/JSON. See: [pfn_error_parse](@ref c4::yml::pfn_error_parse), [ErrorDataParse](@ref c4::yml::ErrorDataParse), [ExceptionParse](@ref c4::yml::ExceptionParse), [err_parse_format()](@ref c4::yml::err_parse_format()), [sample_error_parse](@ref sample_error_parse).
885  - visit error: when visiting a tree (reading or writing). See: [pfn_error_visit](@ref c4::yml::pfn_error_visit), [ErrorDataVisit](@ref c4::yml::ErrorDataVisit), [ExceptionVisit](@ref c4::yml::ExceptionVisit), [err_visit_format()](@ref c4::yml::err_visit_format()), [sample_error_visit](@ref sample_error_visit).
886  - basic error: other, non specific errors. See: [pfn_error_basic](@ref c4::yml::pfn_error_basic), [ErrorDataBasic](@ref c4::yml::ErrorDataBasic), [ExceptionBasic](@ref c4::yml::ExceptionBasic), [err_basic_format()](@ref c4::yml::err_basic_format()), [sample_error_basic](@ref sample_error_basic).
887  - parse and visit errors/exceptions can be treated/caught as basic errors/exceptions.
888  - Add message formatting functions to simplify user-provided implementation of error callbacks:
889  - [err_parse_format()](@ref c4::yml::err_parse_format()): format/print a full error message for a parse error
890  - [err_visit_format()](@ref c4::yml::err_visit_format()): format/print a full error message for a visit error
891  - [err_basic_format()](@ref c4::yml::err_basic_format()): format/print a full error message for a basic error
892  - [location_format()](@ref c4::yml::location_format()): format/print a location
893  - [location_format_with_context()](@ref c4::yml::location_format_with_context()): useful to create a rich error message showing the YAML region causing the error, maybe even for a visit error if the source is kept and locations are enabled.
894  - [format_exc()](@ref c4::yml::format_exc()): format an exception (when exceptions are enabled)
895  - See the new header `c4/yml/error.hpp` (and `c4/yml/error.def.hpp` for definitions of the functions in `c4/yml/error.hpp`)
896  - See the relevant sample functions in the quickstart sample: [sample_error_basic](@ref sample_error_basic), [sample_error_parse](@ref sample_error_parse) and [sample_error_visit](@ref sample_error_visit).
897  - There are breaking user-facing changes in the [Callbacks](@ref c4::yml::Callbacks) structure:
898  - Removed member `m_error`
899  - Added members [m_error_basic](@ref c4::yml::Callbacks::m_error_basic), [m_error_parse](@ref c4::yml::Callbacks::m_error_parse), [m_error_visit](@ref c4::yml::Callbacks::m_error_visit)
900  - Added methods [.set_error_basic()](@ref c4::yml::Callbacks::set_error_basic()), [.set_error_parse()](@ref c4::yml::Callbacks::set_error_parse()) and [.set_error_visit()](@ref c4::yml::Callbacks::set_error_visit()).
901 - **BREAKING** [PR#557](https://github.com/biojppm/rapidyaml/pull/557) - [Tree](@ref c4::yml::Tree) is now non-empty by default, and [.root_id()](@ref c4::yml::Tree::root_id()) will no longer modify the tree when it is empty. To create an empty tree, it is now necessary to use the capacity constructor with a capacity of zero:
902  @code{c++}
903  // breaking change: default-constructed tree is now non-empty
904  Tree tree;
905  assert(!tree.empty()); // MODIFIED! was empty on previous version
906  id_type root = tree.root_id(); // OK. default-constructed tree is now non-empty
907 
908  // to create an empty tree (as happened before):
909  Tree tree(0); // pass capacity of zero
910  assert(tree.empty()); // as expected
911  // but watchout, this is no longer possible:
912  //id_type root = tree.root_id(); // ERROR: cannot get root of empty tree.
913  @endcode
914  This changeset also enables the python library to call `root_id()` on a default-constructed tree (fixes [#556](https://github.com/biojppm/rapidyaml/issues/556)).
915 
916 
917 ### Fixes in YAML parsing
918 
919 - [PR#561](https://github.com/biojppm/rapidyaml/pull/561) (fixes [#559](https://github.com/biojppm/rapidyaml/issues/559)) - Byte Order Mark: account for BOM length when determining block indentation
920 - [PR#547](https://github.com/biojppm/rapidyaml/pull/547) - Fix parsing of implicit first documents with empty sequences, caused by a problem in `Tree::set_root_as_stream()`:
921  @code{yaml}
922  [] # this container was lost during parsing
923  ---
924  more data here
925  @endcode
926 - [PR#576](https://github.com/biojppm/rapidyaml/pull/576) - `extra::events_ints_print()`: Prevent integer overflow in bounds check (thanks [\@bytecodesky](https://github.com/bytecodesky)).
927 
928 
929 ### JSON emitting changes
930 
931 - [PR#574](https://github.com/biojppm/rapidyaml/pull/574) (fixes [#535](https://github.com/biojppm/rapidyaml/issues/535) and [#312](https://github.com/biojppm/rapidyaml/issues/312)) - improve handling of `.inf`, `.nan` and some float formats when emitting to JSON. For example, the tree
932  @code{yaml}
933  {
934  inf: [inf, infinity, .inf, .Inf, .INF, -inf, -infinity, -.inf, -.Inf, -.INF],
935  nan: [nan, .nan, .NaN, .NAN],
936  dot: [.1, 1., .2e2, 10., -.2, -2.],
937  zero: [10, 01],
938  normal: [0.1, 0.2e3, 4.e5],
939  }
940  @endcode
941  is now emitted to JSON as:
942  @code{json}
943  {
944  ".inf": [".inf",".inf",".inf",".inf","-.inf","-.inf","-.inf","-.inf","-.inf","-.inf"],
945  ".nan": [".nan",".nan",".nan",".nan"],
946  "dot": [0.1,1.0,0.2e2,10.0,-0.2,-2.0],
947  "zero": [10,"01"],
948  "normal": [0.1,0.2e3,4.e5]
949  }
950  @endcode
951  Previously, some inf and nan cases were emitted without quotes; now they are all emitted with the fixed strings `.nan` and `.inf`, which helps in cases where the JSON may be loaded in JavaScript. Note also the added zeroes for some floats, eg `.1` or `-2.` turning into `0.1` and `-2.0`.
952 
953 
954 ### Other changes
955 
956 - Update c4core to v0.2.10
957 
958 
959 ### Python improvements
960 
961 - [PR#560](https://github.com/biojppm/rapidyaml/pull/560) (see also [#554](https://github.com/biojppm/rapidyaml/issues/554)): python improvements:
962  - expose `Tree::to_arena()` in python. This allows safer and easier programatic creation of trees in python by ensuring scalars are placed into the tree and so have the same lifetime as the tree:
963  ```python
964  t = ryml.Tree()
965  s = t.to_arena(temp_string()) # Copy/serialize a temporary string to the tree's arena.
966  # Works also with integers and floats.
967  t.to_val(t.root_id(), s) # Now we can safely use the scalar in the tree:
968  # there is no longer any risk of it being deallocated
969  ```
970  - improve behavior of `Tree` methods accepting scalars: all standard buffer types are now accepted (ie, `str`, `bytes`, `bytearray` and `memoryview`).
971 - [PR#565](https://github.com/biojppm/rapidyaml/pull/565) (fixes [#564](https://github.com/biojppm/rapidyaml/issues/564)) - `Tree` arena: allow relocation of zero-length strings when placed at the end (relax assertions triggered in `Tree::_relocated()`)
972 - [PR#563](https://github.com/biojppm/rapidyaml/pull/563) (fixes [#562](https://github.com/biojppm/rapidyaml/issues/562)) - Fix bug in `NodeRef::cend()`
973 - [PR#568](https://github.com/biojppm/rapidyaml/pull/568) - Move `escape_scalar()` from `c4/yml/extra/scalar.hpp` to `c4/yml/escape_scalar.hpp` (and removed the original header)
974 
975 
976 ### Thanks
977 
978 - [\@bytecodesky](https://github.com/bytecodesky)
979 
980 
981 
982 ----------------------------
983 <a name="v0.10.0"></a>
984 ## 0.10.0
985 
986 [Github release: 0.10.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.10.0)
987 
988 ### Extra event handlers
989 
990 [PR#536](https://github.com/biojppm/rapidyaml/pull/536) adds a new major extra feature: a parser event handler that creates a compact representation of the YAML tree in a buffer of integers containing masks (to represent events) and offset+length (to represent strings in the source buffer).
991 
992 This handler is meant for use by other programming languages, and it supports container keys (unlike the ryml tree). You can find this handler among the other headers in the [new `src_extra` folder](https://github.com/biojppm/rapidyaml/tree/master/src_extra).
993 
994 
995 ### Changes
996 
997 - In [PR#536](https://github.com/biojppm/rapidyaml/pull/536) the location functions were moved from `ParserEngine` to `Tree` and `ConstNodeRef`. The parser engine is now fully agnostic vis-a-vis the type of the event-handler. (The location functions in the parser engine were a legacy of the initial implementation of the parser which was meant to create only ryml trees).
998 - The tool ryml-yaml-events was updated to also dump integer events (and its command line options were changed to enable the different choices).
999 
1000 
1001 ### Fixes
1002 
1003 - Fix [#524](https://github.com/biojppm/rapidyaml/issues/524) ([PR#525](https://github.com/biojppm/rapidyaml/pull/525)): problem parsing nested map value in complex map. Kudos to [\@MatthewSteel](https://github.com/MatthewSteel)!
1004 - [PR#542](https://github.com/biojppm/rapidyaml/pull/542): `\x` Unicode sequences were not decoded. Thanks to [\@mutativesystems](https://github.com/mutativesystems)!
1005 - [PR#541](https://github.com/biojppm/rapidyaml/pull/541): `std::is_trivial` deprecated in c++26. Thanks to [\@P3RK4N](https://github.com/P3RK4N)!
1006 - Fix [#529](https://github.com/biojppm/rapidyaml/issues/529) ([PR#530](https://github.com/biojppm/rapidyaml/pull/530)): double-quoted `"<<"` was mistaken for an inheriting reference.
1007 - [PR#543](https://github.com/biojppm/rapidyaml/pull/543): improvements to experimental style API:
1008  - Add getters to [NodeType](@ref c4::yml::NodeType), [Tree](@ref c4::yml::Tree), [NodeRef](@ref c4::yml::NodeRef), and [ConstNodeRef](@ref c4::yml::ConstNodeRef):
1009  - `.key_style()`: get the style flags in a node's key
1010  - `.val_style()`: get the style flags in a node's val
1011  - `.container_style()`: get the style flags in a node's container
1012  - Add style modifiers to [NodeType](@ref c4::yml::NodeType), [Tree](@ref c4::yml::Tree), [NodeRef](@ref c4::yml::NodeRef), and [ConstNodeRef](@ref c4::yml::ConstNodeRef):
1013  - `.clear_style(bool recurse)`
1014  - `.set_style_conditionally(bool recurse)`
1015 - Fix argument handling in ryml-parse-emit.
1016 
1017 
1018 ### Thanks
1019 
1020 - [\@MatthewSteel](https://github.com/MatthewSteel)
1021 - [\@mutativesystems](https://github.com/mutativesystems)
1022 - [\@P3RK4N](https://github.com/P3RK4N)
1023 
1024 
1025 ----------------------------
1026 <a name="v0.9.0"></a>
1027 ## 0.9.0
1028 
1029 [Github release: 0.9.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.9.0)
1030 
1031 
1032 ### Fixes
1033 
1034 - Fix [#400](https://github.com/biojppm/rapidyaml/issues/400) ([PR#506](https://github.com/biojppm/rapidyaml/pull/506)): clear anchors after resolving.
1035 - Fix [#484](https://github.com/biojppm/rapidyaml/issues/484) ([PR#506](https://github.com/biojppm/rapidyaml/pull/506)): fix merge key order for last element to be overriden.
1036 - [PR#503](https://github.com/biojppm/rapidyaml/pull/503): ensure parse error on `a: b: c` and similar cases containing nested maps opening on the same line.
1037 - [PR#502](https://github.com/biojppm/rapidyaml/pull/502): fix parse errors or missing tags:
1038  - missing tags in empty documents:
1039  @code{yaml}
1040  !yamlscript/v0/bare
1041  --- !code
1042  42
1043  @endcode
1044  - trailing empty keys or vals:
1045  @code{yaml}
1046  a:
1047  :
1048  @endcode
1049  - missing tags in trailing empty keys or vals:
1050  @code{yaml}
1051  a: !tag
1052  !tag : !tag
1053  @endcode
1054  - missing tags in complex maps:
1055  @code{yaml}
1056  ? a: !tag
1057  !tag : !tag
1058  :
1059  !tag : !tag
1060  @endcode
1061 - [PR#501](https://github.com/biojppm/rapidyaml/pull/501): fix missing tag in `- !!seq []`.
1062 - [PR#508](https://github.com/biojppm/rapidyaml/pull/508): fix build with cmake 4.
1063 - [PR#517](https://github.com/biojppm/rapidyaml/pull/517) (fixes [#516](https://github.com/biojppm/rapidyaml/issues/516)): fix python wheels for windows and macosx.
1064 - Fix [#120](https://github.com/biojppm/rapidyaml/issues/120) (again): add workaround for `#define` emit in Qt
1065 
1066 
1067 ### Thanks
1068 
1069 - [\@davidrudlstorfer](https://github.com/davidrudlstorfer)
1070 
1071 
1072 ----------------------------
1073 <a name="v0.8.0"></a>
1074 ## 0.8.0
1075 
1076 [Github release: 0.8.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.8.0)
1077 
1078 ### Breaking changes
1079 
1080 - [BREAKING] Fix [#480](https://github.com/biojppm/rapidyaml/issues/480) ([PR#489](https://github.com/biojppm/rapidyaml/pull/489)):
1081  - Deserializing an empty quoted string *will not* cause an error.
1082  - Deserializing an empty string *will* cause an error: the empty string is read in as an empty scalar.
1083  - Ensure keys are deserialized using all the rules applying to vals.
1084  - Added [KEYNIL](@ref c4::yml::NodeTypeBits::KEYNIL) and [VALNIL](@ref c4::yml::NodeTypeBits::VALNIL) to [NodeType_e](@ref c4::yml::NodeTypeBits), used by the parser to mark the key or val as empty. This changed the values of the [NodeType_e](@ref c4::yml::NodeTypeBits) enumeration.
1085  - Added `.key_is_null()` and `.val_is_null()`:
1086  - [NodeType](@ref c4::yml::NodeType): [.key_is_null()](@ref c4::yml::NodeType::key_is_null()) and [.val_is_null()](@ref c4::yml::NodeType::val_is_null())
1087  - [Tree](@ref c4::yml::Tree): [.key_is_null()](@ref c4::yml::Tree::key_is_null()) and [.val_is_null()](@ref c4::yml::Tree::val_is_null())
1088  - [ConstNodeRef](@ref c4::yml::ConstNodeRef): [.key_is_null()](@ref c4::yml::ConstNodeRef::key_is_null()) and [.val_is_null()](@ref c4::yml::ConstNodeRef::val_is_null())
1089  - [NodeRef](@ref c4::yml::NodeRef): [.key_is_null()](@ref c4::yml::NodeRef::key_is_null()) and [.val_is_null()](@ref c4::yml::NodeRef::val_is_null())
1090 - [BREAKING] Fix [#477](https://github.com/biojppm/rapidyaml/issues/477) ([PR#479](https://github.com/biojppm/rapidyaml/pull/479)): changed [`read<std::map>()`](@ref c4/yml/std/map.hpp) to overwrite existing entries. The provided implementations had an inconsistency between [`read<std::map>()`](@ref c4/yml/std/map.hpp) (which wasn't overwriting) and [`read<std:vector>()`](@ref c4/yml/std/vector.hpp) (which *was* overwriting).
1091 
1092 
1093 ### Fixes
1094 
1095 - [PR#488](https://github.com/biojppm/rapidyaml/pull/488):
1096  - add workarounds for problems with codegen of gcc 11,12,13.
1097  - improve CI coverage of gcc and clang optimization levels.
1098 - [PR#496](https://github.com/biojppm/rapidyaml/pull/496) and [c4core PR#148](https://github.com/biojppm/c4core/pull/148): Add CI-proven support for CPU architectures:
1099  - mips, mipsel, mips64, mips64el
1100  - sparc, sparc64
1101  - riscv64
1102  - loongarch64
1103 - Fix [#476](https://github.com/biojppm/rapidyaml/issues/476) ([PR#493](https://github.com/biojppm/rapidyaml/pull/493)): add handling of Byte Order Marks.
1104 - [PR#492](https://github.com/biojppm/rapidyaml/pull/492): fix emit of explicit keys when indented:
1105  @code{yaml}
1106  fixed:
1107  ? explicit key
1108  : value
1109  previously:
1110  ? explicit key
1111  : value # this was not indented
1112  @endcode
1113 - [PR#492](https://github.com/biojppm/rapidyaml/pull/492): fix parser reset for full reuse (`m_doc_empty` was not resetted), which would cause problems under specific scenarios in subsequent reuse.
1114 - [PR#485](https://github.com/biojppm/rapidyaml/pull/485): improve the CI workflows (thanks to [\@ingydotnet](https://github.com/ingydotnet)):
1115  - amazing code reuse and organization, thanks to the use of YamlScript to generate the final workflows
1116  - all optimization levels are now covered for gcc, clang and Visual Studio.
1117 - [PR#499](https://github.com/biojppm/rapidyaml/pull/499): fix warnings with `-Wundef`.
1118 
1119 
1120 ### Thanks
1121 
1122 - [\@ingydotnet](https://github.com/ingydotnet)
1123 - [\@perlpunk](https://github.com/perlpunk)
1124 - [\@Delian0](https://github.com/Delian0)
1125 
1126 
1127 ---------------------------------------
1128 <a name="v0.7.2"></a>
1129 ## 0.7.2
1130 - [0.7.2](https://github.com/biojppm/rapidyaml/releases/tag/v0.7.2)
1131 
1132 ### Fixes
1133 
1134 - Fix [#464](https://github.com/biojppm/rapidyaml/issues/464): test failures with g++14 -O2 in ppc64le ([PR#467](https://github.com/biojppm/rapidyaml/pull/467))
1135 
1136 
1137 ### Thanks
1138 
1139 - [\@musicinmybrain](https://github.com/musicinmybrain)
1140 
1141 
1142 ---------------------------------------
1143 <a name="v0.7.1"></a>
1144 ## 0.7.1
1145 [Github release: 0.7.1](https://github.com/biojppm/rapidyaml/releases/tag/v0.7.1)
1146 
1147 ### New features
1148 
1149 - [PR#459](https://github.com/biojppm/rapidyaml/pull/459): Add [version functions and macros](@ref c4/yml/version.hpp):
1150  @code{c++}
1151  #define RYML_VERSION "0.7.1"
1152  #define RYML_VERSION_MAJOR 0
1153  #define RYML_VERSION_MINOR 7
1154  #define RYML_VERSION_PATCH 1
1155  csubstr version();
1156  int version_major();
1157  int version_minor();
1158  int version_patch();
1159  @endcode
1160 
1161 ### Fixes
1162 
1163 - Fix [#455](https://github.com/biojppm/rapidyaml/issues/455): parsing of trailing val-less nested maps when deindented to maps ([PR#460](https://github.com/biojppm/rapidyaml/pull/460))
1164 - Fix filtering of double-quoted keys in block maps ([PR#452](https://github.com/biojppm/rapidyaml/pull/452))
1165 - Fix [#440](https://github.com/biojppm/rapidyaml/issues/440): some tests failing with gcc -O2 (hypothetically due to undefined behavior)
1166  - This was accomplished by refactoring some internal parser functions; see the comments in [#440](https://github.com/biojppm/rapidyaml/issues/440) for further details.
1167  - Also, fix all warnings from `scan-build`.
1168 - Use malloc.h instead of alloca.h on MinGW ([PR#447](https://github.com/biojppm/rapidyaml/pull/447))
1169 - Fix [#442](https://github.com/biojppm/rapidyaml/issues/442) ([PR#443](https://github.com/biojppm/rapidyaml/pull/443)):
1170  - Ensure leading `+` is accepted when deserializing numbers.
1171  - Ensure numbers are not quoted by fixing the heuristics in `scalar_style_query_plain()` and `scalar_style_choose()`.
1172  - Add quickstart sample for overflow detection (only of integral types).
1173 - Parse engine: cleanup unused macros
1174 
1175 
1176 ### Thanks
1177 
1178 - [\@marcalff](https://github.com/marcalff)
1179 - [\@toge](https://github.com/toge)
1180 - [\@musicinmybrain](https://github.com/musicinmybrain)
1181 - [\@buty4649](https://github.com/buty4649)
1182 
1183 
1184 ---------------------------------------
1185 <a name="v0.7.0"></a>
1186 ## 0.7.0
1187 [Github release: 0.7.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.7.0)
1188 
1189 Most of the changes are from the giant Parser refactor described below. Before getting to that, some other minor changes first.
1190 
1191 
1192 ### Fixes
1193 
1194 - [PR#431](https://github.com/biojppm/rapidyaml/pull/431) - Emitter: prevent stack overflows when emitting malicious trees by providing a max tree depth for the emit visitor. This was done by adding an `EmitOptions` structure as an argument both to the emitter and to the emit functions, which is then forwarded to the emitter. This `EmitOptions` structure has a max tree depth setting with a default value of 64.
1195 - [PR#431](https://github.com/biojppm/rapidyaml/pull/431) - Fix `_RYML_CB_ALLOC()` using `(T)` in parenthesis, making the macro unusable.
1196 - [#434](https://github.com/biojppm/rapidyaml/issues/434) - Ensure empty vals are not deserialized ([PR#436](https://github.com/biojppm/rapidyaml/pull/436)).
1197 - [PR#433](https://github.com/biojppm/rapidyaml/pull/433):
1198  - Fix some corner cases causing read-after-free in the tree's arena when it is relocated while filtering scalars.
1199  - Improve YAML error conformance - detect YAML-mandated parse errors when:
1200  - directives are misplaced (eg [9MMA](https://matrix.yaml.info/details/9MMA.html), [9HCY](https://matrix.yaml.info/details/9HCY.html), [B63P](https://matrix.yaml.info/details/B63P.html), [EB22](https://matrix.yaml.info/details/EB22.html), [SF5V](https://matrix.yaml.info/details/SF5V.html)).
1201  - comments are misplaced (eg [MUS6/00](https://matrix.yaml.info/details/MUS6:00.html), [9JBA](https://matrix.yaml.info/details/9JBA.html), [SU5Z](https://matrix.yaml.info/details/SU5Z.html))
1202  - a node has both an anchor and an alias (eg [SR86](https://matrix.yaml.info/details/SR86.html), [SU74](https://matrix.yaml.info/details/SU74.html)).
1203  - tags contain [invalid characters](https://yaml.org/spec/1.2.2/#tag-shorthands) `,{}[]` (eg [LHL4](https://matrix.yaml.info/details/LHL4.html), [U99R](https://matrix.yaml.info/details/U99R.html), [WZ62](https://matrix.yaml.info/details/WZ62.html)).
1204 
1205 
1206 ### New features
1207 
1208 - [PR#431](https://github.com/biojppm/rapidyaml/pull/431) - append-emitting to existing containers in the `emitrs_` functions, suggested in [#345](https://github.com/biojppm/rapidyaml/issues/345). This was achieved by adding a `bool append=false` as the last parameter of these functions.
1209 - [PR#431](https://github.com/biojppm/rapidyaml/pull/431) - add depth query methods:
1210  @code{c++}
1211  Tree::depth_asc(id_type) const; // O(log(num_tree_nodes)) get the depth of a node ascending (ie, from root to node)
1212  Tree::depth_desc(id_type) const; // O(num_tree_nodes) get the depth of a node descending (ie, from node to deep-most leaf node)
1213  ConstNodeRef::depth_asc() const; // likewise
1214  ConstNodeRef::depth_desc() const;
1215  NodeRef::depth_asc() const;
1216  NodeRef::depth_desc() const;
1217  @endcode
1218 - [PR#432](https://github.com/biojppm/rapidyaml/pull/432) - Added a function to estimate the required tree capacity, based on yaml markup:
1219  @code{c++}
1220  size_t estimate_tree_capacity(csubstr); // estimate number of nodes resulting from yaml
1221  @endcode
1222 
1223 
1224 ------
1225 All other changes come from [PR#414](https://github.com/biojppm/rapidyaml/pull/414).
1226 
1227 ### Parser refactor
1228 
1229 The parser was completely refactored ([PR#414](https://github.com/biojppm/rapidyaml/pull/414)). This was a large and hard job carried out over several months, but it brings important improvements.
1230 
1231 - The new parser is an event-based parser, based on an event dispatcher engine. This engine is templated on event handler, where each event is a function call, which spares branches on the event handler. The parsing code was fully rewritten, and is now much more simple (albeit longer), and much easier to work with and fix.
1232 - YAML standard-conformance was improved significantly. Along with many smaller fixes and additions, (too many to list here), the main changes are the following:
1233  - The parser engine can now successfully parse container keys, emitting all the events in correctly, **but** as before, the ryml tree cannot accomodate these (and this constraint is no longer enforced by the parser, but instead by `EventHandlerTree`). For an example of a handler which can accomodate key containers, see the one which is used for the test suite at `test/test_suite/test_suite_event_handler.hpp`
1234  - Anchor keys can now be terminated with colon (eg, `&anchor: key: val`), as dictated by the standard.
1235 - The parser engine can now be used to create native trees in other programming languages, or in cases where the user *must* have container keys.
1236 - Performance of both parsing and emitting improved significantly; see some figures below.
1237 
1238 
1239 ### Strict JSON parser
1240 
1241 - A strict JSON parser was added. Use the `parse_json_...()` family of functions to parse json in stricter mode (and faster) than flow-style YAML.
1242 
1243 
1244 ### YAML style preserved while parsing
1245 
1246 - The YAML style information is now fully preserved through parsing/emitting round trips. This was made possible because the event model of the new parsing engine now incorporates style varieties. So, for example:
1247  - a scalar parsed from a plain/single-quoted/double-quoted/block-literal/block-folded scalar will be emitted always using its original style in the YAML source
1248  - a container parsed in block-style will always be emitted in block-style
1249  - a container parsed in flow-style will always be emitted in flow-style
1250  Because of this, the style of YAML emitted by ryml changes from previous releases.
1251 - Scalar filtering was improved and is now done directly in the source being parsed (which may be in place or in the arena), except in the cases where the scalar expands and does not fit its initial range, in which case the scalar is filtered out of place to the tree's arena.
1252  - Filtering can now be disabled while parsing, to ensure a fully-readonly parse (but this feature is still experimental and somewhat untested, given the scope of the rewrite work).
1253  - The parser now offers methods to filter scalars in place or out of place.
1254 - Style flags were added to `NodeType_e`:
1255  @code{c++}
1256  FLOW_SL ///< mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,key2: val2}')
1257  FLOW_ML ///< mark container with multi-line flow style (seqs as '[\n val1,\n val2\n], maps as '{\n key: val,\n key2: val2\n}')
1258  BLOCK ///< mark container with block style (seqs as '- val\n', maps as 'key: val')
1259  KEY_LITERAL ///< mark key scalar as multiline, block literal |
1260  VAL_LITERAL ///< mark val scalar as multiline, block literal |
1261  KEY_FOLDED ///< mark key scalar as multiline, block folded >
1262  VAL_FOLDED ///< mark val scalar as multiline, block folded >
1263  KEY_SQUO ///< mark key scalar as single quoted '
1264  VAL_SQUO ///< mark val scalar as single quoted '
1265  KEY_DQUO ///< mark key scalar as double quoted "
1266  VAL_DQUO ///< mark val scalar as double quoted "
1267  KEY_PLAIN ///< mark key scalar as plain scalar (unquoted, even when multiline)
1268  VAL_PLAIN ///< mark val scalar as plain scalar (unquoted, even when multiline)
1269  @endcode
1270 - Style predicates were added to `NodeType`, `Tree`, `ConstNodeRef` and `NodeRef`:
1271  @code{c++}
1272  bool is_container_styled() const;
1273  bool is_block() const
1274  bool is_flow_sl() const;
1275  bool is_flow_ml() const;
1276  bool is_flow() const;
1277 
1278  bool is_key_styled() const;
1279  bool is_val_styled() const;
1280  bool is_key_literal() const;
1281  bool is_val_literal() const;
1282  bool is_key_folded() const;
1283  bool is_val_folded() const;
1284  bool is_key_squo() const;
1285  bool is_val_squo() const;
1286  bool is_key_dquo() const;
1287  bool is_val_dquo() const;
1288  bool is_key_plain() const;
1289  bool is_val_plain() const;
1290  @endcode
1291 - Style modifiers were also added:
1292  @code{c++}
1293  void set_container_style(NodeType_e style);
1294  void set_key_style(NodeType_e style);
1295  void set_val_style(NodeType_e style);
1296  @endcode
1297 - Emit helper predicates were added, and are used when an emitted node was built programatically without style flags:
1298  @code{c++}
1299  /** choose a YAML emitting style based on the scalar's contents */
1300  NodeType_e scalar_style_choose(csubstr scalar) noexcept;
1301  /** query whether a scalar can be encoded using single quotes.
1302  * It may not be possible, notably when there is leading
1303  * whitespace after a newline. */
1304  bool scalar_style_query_squo(csubstr s) noexcept;
1305  /** query whether a scalar can be encoded using plain style (no
1306  * quotes, not a literal/folded block scalar). */
1307  bool scalar_style_query_plain(csubstr s) noexcept;
1308  @endcode
1309 
1310 ### Breaking changes
1311 
1312 As a result of the refactor, there are some limited changes with impact in client code. Even though this was a large refactor, effort was directed at keeping maximal backwards compatibility, and the changes are not wide. But they still exist:
1313 
1314 - The existing `parse_...()` methods in the `Parser` class were all removed. Use the corresponding `parse_...(Parser*, ...)` function from the header [`c4/yml/parse.hpp`](https://github.com/biojppm/rapidyaml/blob/master/src/c4/yml/parse.hpp).
1315 - When instantiated by the user, the parser now needs to receive a `EventHandlerTree` object, which is responsible for building the tree. Although fully functional and tested, the structure of this class is still somewhat experimental and is still likely to change. There is an alternative event handler implementation responsible for producing the events for the YAML test suite in `test/test_suite/test_suite_event_handler.hpp`.
1316 - The declaration and definition of `NodeType` was moved to a separate header file `c4/yml/node_type.hpp` (previously it was in `c4/yml/tree.hpp`).
1317 - Some of the node type flags were removed, and several flags (and combination flags) were added.
1318  - Most of the existing flags are kept, as well as their meaning.
1319  - `KEYQUO` and `VALQUO` are now masks of the several style flags for quoted scalars. In general, however, client code using these flags and `.is_val_quoted()` or `.is_key_quoted()` is not likely to require any changes.
1320 
1321 
1322 ### New type for node IDs
1323 
1324 A type `id_type` was added to signify the integer type for the node id, defaulting to the backwards-compatible `size_t` which was previously used in the tree. In the future, this type is likely to change, *and probably to a signed type*, so client code is encouraged to always use `id_type` instead of the `size_t`, and specifically not to rely on the signedness of this type.
1325 
1326 
1327 ### Reference resolver is now exposed
1328 
1329 The reference (ie, alias) resolver object is now exposed in
1330 [`c4/yml/reference_resolver.hpp`](https://github.com/biojppm/rapidyaml/blob/master/src/c4/yml/reference_resolver.hpp). Previously this object was temporarily instantiated in `Tree::resolve()`. Exposing it now enables the user to reuse this object through different calls, saving a potential allocation on every call.
1331 
1332 
1333 ### Tag utilities
1334 
1335 Tag utilities were moved to the new header [`c4/yml/tag.hpp`](https://github.com/biojppm/rapidyaml/blob/master/src/c4/yml/tag.hpp). The types `Tree::tag_directive_const_iterator` and `Tree::TagDirectiveProxy` were deprecated. Fixed also an unitialization problem with `Tree::m_tag_directives`.
1336 
1337 
1338 ### Performance improvements
1339 
1340 To compare performance before and after this changeset, the benchmark runs were run (in the same PC), and the results were collected into these two files:
1341  - [results before newparser](https://github.com/biojppm/rapidyaml/blob/master/bm/results/results_before_newparser.md)
1342  - [results after newparser](https://github.com/biojppm/rapidyaml/blob/master/bm/results/results_after_newparser.md)
1343  - (suggestion: compare these files in a diff viewer)
1344 
1345 There are a lot of results in these files, and many insights can be obtained by browsing them; too many to list here. Below we show only some selected results.
1346 
1347 
1348 #### Parsing
1349 Here are some figures for parsing performance, for `bm_ryml_inplace_reuse` (name before) / `bm_ryml_yaml_inplace_reuse` (name after):
1350 
1351 |------|------------|-----------|--------|
1352 | case | B/s before newparser | B/s after newparser | improv % |
1353 |------|------------|-----------|--------|
1354 | [PARSE/appveyor.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/appveyor.yml) | 168.628Mi/s | 232.017Mi/s | ~+40% |
1355 | [PARSE/compile_commands.json](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/compile_commands.yml) | 630.17Mi/s | 609.877Mi/s | ~-3% |
1356 | [PARSE/travis.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/travis.yml) | 193.674Mi/s | 271.598Mi/s | ~+50% |
1357 | [PARSE/scalar_dquot_multiline.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/scalar_dquot_multiline.yml) | 224.796Mi/s | 187.335Mi/s | ~-10% |
1358 | [PARSE/scalar_dquot_singleline.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/scalar_dquot_singleline.yml) | 339.889Mi/s | 388.924Mi/s | ~-16% |
1359 
1360 Some conclusions:
1361 - parse performance improved by ~30%-50% for YAML without filtering-heavy parsing.
1362 - parse performance *decreased* by ~10%-15% for YAML with filtering-heavy parsing. There is still some scope for improvement in the parsing code, so this cost may hopefully be minimized in the future.
1363 
1364 
1365 #### Emitting
1366 
1367 Here are some figures emitting performance improvements retrieved from these files, for `bm_ryml_str_reserve` (name before) / `bm_ryml_yaml_str_reserve` (name after):
1368 
1369 |------|------------|-----------|
1370 | case | B/s before newparser | B/s after newparser |
1371 |------|------------|-----------|
1372 | [EMIT/appveyor.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/appveyor.yml) | 311.718Mi/s | 1018.44Mi/s |
1373 | [EMIT/compile_commands.json](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/compile_commands.yml) | 434.206Mi/s | 771.682Mi/s |
1374 | [EMIT/travis.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/travis.yml) | 333.322Mi/s | 1.41597Gi/s |
1375 | [EMIT/scalar_dquot_multiline.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/scalar_dquot_multiline.yml) | 868.6Mi/s | 692.564Mi/s |
1376 | [EMIT/scalar_dquot_singleline.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/scalar_dquot_singleline.yml) | 336.98Mi/s | 638.368Mi/s |
1377 | [EMIT/style_seqs_flow_outer1000_inner100.yml](https://github.com/biojppm/rapidyaml/blob/master/bm/cases/style_seqs_flow_outer1000_inner100.yml) | 136.826Mi/s | 279.487Mi/s |
1378 
1379 Emit performance improved everywhere by over 1.5x and as much as 3x-4x for YAML without filtering-heavy parsing.
1380 
1381 
1382 ---------------------------------------
1383 <a name="v0.6.0"></a>
1384 ## 0.6.0
1385 [Github release: 0.6.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.6.0)
1386 
1387 ### Add API documentation
1388 
1389 - [PR#423](https://github.com/biojppm/rapidyaml/pull/423): **add Doxygen-based API documentation, now hosted in [https://rapidyaml.readthedocs.io/](https://rapidyaml.readthedocs.io/)!**
1390 - It uses the base doxygen docs, as I couldn't get doxyrest or breathe or exhale to produce anything meaningful using the doxygen groups already defined in the source code.
1391 
1392 
1393 ### Error handling
1394 
1395 Fix major error handling problem reported in [#389](https://github.com/biojppm/rapidyaml/issues/389) ([PR#411](https://github.com/biojppm/rapidyaml/pull/411)):
1396 
1397  - The [NodeRef](@ref c4::yml::NodeRef) and [ConstNodeRef](@ref c4::yml::ConstNodeRef) classes are now conditional `noexcept` using `RYML_NOEXCEPT`, which evaluates either to nothing when assertions are enabled, and to `noexcept` otherwise. The problem was that these classes had many methods explicitly marked `noexcept`, but were doing assertions which could throw exceptions, causing an abort instead of a throw whenever the assertion called an exception-throwing error callback.
1398  - This problem was compounded by assertions being enabled in every build type -- despite the intention to have them only in debug builds. There was a problem in the preprocessor code to enable assertions which led to assertions being enabled in release builds even when `RYML_USE_ASSERT` was defined to 0. Thanks to [\@jdrouhard](https://github.com/jdrouhard) for reporting this.
1399  - Although the code is and was extensively tested, the testing was addressing mostly the happy path. Tests were added to ensure that the error behavior is as intended.
1400  - Together with this changeset, a major revision was carried out of the asserting/checking status of each function in the node classes. In most cases, assertions were added to functions that were missing them. So **beware** - some user code that was invalid will now assert or error out. Also, assertions and checks are now directed as much as possible to the callbacks of the closest scope: ie, if a tree has custom callbacks, errors within the tree class should go through those callbacks.
1401  - Also, the intended assertion behavior is now in place: *no assertions in release builds*. **Beware** as well - user code which was relying on this will now silently succeed and return garbage in release builds. See the next points, which may help.
1402  - Added new methods to the [NodeRef](@ref c4::yml::NodeRef)/[ConstNodeRef](@ref c4::yml::ConstNodeRef) classes:
1403  - `.readable()`: [NodeRef::readable()](@ref c4::yml::NodeRef::readable()) and [ConstNodeRef::readable()](@ref c4::yml::ConstNodeRef::readable())
1404  - `.at()`: [NodeRef::at()](@ref c4::yml::NodeRef::at()) and [ConstNodeRef::at()](@ref c4::yml::ConstNodeRef::at())
1405  - The state for [NodeRef](@ref c4::yml::NodeRef) was refined, and now there are three mutually exclusive states (and class predicates) for an object of this class:
1406  - [.invalid()](@ref c4::yml::NodeRef::invalid()) when the object was not initialized to any node
1407  - [.readable()](@ref c4::yml::NodeRef::readable()) when the object points at an existing tree+node
1408  - [.is_seed()](@ref c4::yml::NodeRef::is_seed()) when the object points at an hypotethic tree+node
1409  - The previous state `.valid()` was deprecated: its semantics were confusing as it actually could be any of `.readable()` or `.is_seed()`
1410  - Deprecated also the following methods for [NodeRef](@ref c4::yml::NodeRef)/[ConstNodeRef](@ref c4::yml::ConstNodeRef):
1411  @code{c++}
1412  RYML_DEPRECATED() bool operator== (std::nullptr_t) const;
1413  RYML_DEPRECATED() bool operator!= (std::nullptr_t) const;
1414  RYML_DEPRECATED() bool operator== (csubstr val) const;
1415  RYML_DEPRECATED() bool operator!= (csubstr val) const;
1416  @endcode
1417  - Added macros and respective cmake options to control error handling:
1418  - `RYML_USE_ASSERT` - enable assertions regardless of build type. This is disabled by default. This macro was already defined; the current PR adds the cmake option.
1419  - `RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS` - make the default error handler provided by ryml throw exceptions instead of calling `std::abort()`. This is disabled by default.
1420  - Also, `RYML_DEBUG_BREAK()` is now enabled only if `RYML_DBG` is defined, as reported in [#362](https://github.com/biojppm/rapidyaml/issues/362).
1421  - As part of [PR#423](https://github.com/biojppm/rapidyaml/pull/423), to improve linters and codegen:
1422  - annotate the error handlers with `[[noreturn]]`/`C4_NORETURN`
1423  - annotate some error sites with `C4_UNREACHABLE_AFTER_ERR()`
1424 
1425 
1426 ### More fixes
1427 
1428 - `Tree::arena() const` was returning a `substr`; this was an error. This function was changed to:
1429  ```
1430  csubstr Tree::arena() const;
1431  substr Tree::arena();
1432  ```
1433 - Fix [#390](https://github.com/biojppm/rapidyaml/issues/390) - `csubstr::first_real_span()` failed on scientific numbers with one digit in the exponent ([PR#415](https://github.com/biojppm/rapidyaml/pull/415)).
1434 - Fix [#361](https://github.com/biojppm/rapidyaml/issues/361) - parse error on map scalars containing `:` and starting on the next line:
1435  @code{yaml}
1436  ---
1437  # failed to parse:
1438  description:
1439  foo:bar
1440  ---
1441  # but this was ok:
1442  description: foo:bar
1443  @endcode
1444 - [PR#368](https://github.com/biojppm/rapidyaml/pull/368) - fix pedantic compiler warnings.
1445 - Fix [#373](https://github.com/biojppm/rapidyaml/issues/373) - false parse error with empty quoted keys in block-style map ([PR#374](https://github.com/biojppm/rapidyaml/pull/374)).
1446 - Fix [#356](https://github.com/biojppm/rapidyaml/issues/356) - fix overzealous check in `emit_as()`. An id may be larger than the tree's size, eg when nodes were removed. ([PR#357](https://github.com/biojppm/rapidyaml/pull/357)).
1447 - Fix [#417](https://github.com/biojppm/rapidyaml/issues/417) - add quickstart example explaining how to avoid precision loss while serializing floats ([PR#420](https://github.com/biojppm/rapidyaml/pull/420)).
1448 - Fix [#380](https://github.com/biojppm/rapidyaml/issues/380) - Debug visualizer .natvis file for Visual Studio was missing [ConstNodeRef](@ref c4::yml::ConstNodeRef) ([PR#383](https://github.com/biojppm/rapidyaml/issues/383)).
1449 - FR [#403](https://github.com/biojppm/rapidyaml/issues/403) - install is now optional when using cmake. The relevant option is `RYML_INSTALL`.
1450 
1451 
1452 ### Python
1453 
1454 - Fix [#428](https://github.com/biojppm/rapidyaml/issues/428)/[#412](https://github.com/biojppm/rapidyaml/discussions/412) - Parse errors now throw `RuntimeError` instead of aborting.
1455 
1456 
1457 
1458 ### Thanks
1459 
1460 - [\@Neko-Box-Coder](https://github.com/Neko-Box-Coder)
1461 - [\@jdrouhard](https://github.com/jdrouhard)
1462 - [\@dmachaj](https://github.com/dmachaj)
1463 
1464 
1465 ---------------------------------------
1466 <a name="v0.5.0"></a>
1467 ## 0.5.0
1468 [Github release: 0.5.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.5.0)
1469 
1470 ### Breaking changes
1471 
1472 - Make the node API const-correct ([PR#267](https://github.com/biojppm/rapidyaml/pull/267)): added `ConstNodeRef` to hold a constant reference to a node. As the name implies, a `ConstNodeRef` object cannot be used in any tree-mutating operation. It is also smaller than the existing `NodeRef` (and faster because it does not need to check its own validity on every access). As a result of this change, there are now some constraints when obtaining a ref from a tree, and existing code is likely to break in this type of situation:
1473  @code{c++}
1474  const Tree const_tree = ...;
1475  NodeRef nr = const_tree.rootref(); // ERROR (was ok): cannot obtain a mutating NodeRef from a const Tree
1476  ConstNodeRef cnr = const_tree.rootref(); // ok
1477 
1478  Tree tree = ...;
1479  NodeRef nr = tree.rootref(); // ok
1480  ConstNodeRef cnr = tree.rootref(); // ok (implicit conversion from NodeRef to ConstNodeRef)
1481  // to obtain a ConstNodeRef from a mutable Tree
1482  // while avoiding implicit conversion, use the `c`
1483  // prefix:
1484  ConstNodeRef cnr = tree.crootref();
1485  // likewise for tree.ref() and tree.cref().
1486 
1487  nr = cnr; // ERROR: cannot obtain NodeRef from ConstNodeRef
1488  cnr = nr; // ok
1489  @endcode
1490  The use of `ConstNodeRef` also needs to be propagated through client code. One such place is when deserializing types:
1491  @code{c++}
1492  // needs to be changed from:
1493  template<class T> bool read(ryml::NodeRef const& n, T *var);
1494  // ... to:
1495  template<class T> bool read(ryml::ConstNodeRef const& n, T *var);
1496  @endcode
1497  - The initial version of `ConstNodeRef/NodeRef` had the problem that const methods in the CRTP base did not participate in overload resolution ([#294](https://github.com/biojppm/rapidyaml/issues/294)), preventing calls from `const NodeRef` objects. This was fixed by moving non-const methods to the CRTP base and disabling them with SFINAE ([PR#295](https://github.com/biojppm/rapidyaml/pull/295)).
1498  - Also added disambiguation iteration methods: `.cbegin()`, `.cend()`, `.cchildren()`, `.csiblings()` ([PR#295](https://github.com/biojppm/rapidyaml/pull/295)).
1499 - Deprecate `emit()` and `emitrs()` ([#120](https://github.com/biojppm/rapidyaml/issues/120), [PR#303](https://github.com/biojppm/rapidyaml/pull/303)): use `emit_yaml()` and `emitrs_yaml()` instead. This was done to improve compatibility with Qt, which leaks a macro named `emit`. For more information, see [#120](https://github.com/biojppm/rapidyaml/issues/120).
1500  - In the Python API:
1501  - Deprecate `emit()`, add `emit_yaml()` and `emit_json()`.
1502  - Deprecate `compute_emit_length()`, add `compute_emit_yaml_length()` and `compute_emit_json_length()`.
1503  - Deprecate `emit_in_place()`, add `emit_yaml_in_place()` and `emit_json_in_place()`.
1504  - Calling the deprecated functions will now trigger a warning.
1505 - Location querying is no longer done lazily ([#260](https://github.com/biojppm/rapidyaml/issues/260), [PR#307](https://github.com/biojppm/rapidyaml/pull/307)). It now requires explicit opt-in when instantiating the parser. With this change, the accelerator structure for location querying is now built when parsing:
1506  @code{c++}
1507  Parser parser(ParserOptions().locations(true));
1508  // now parsing also builds location lookup:
1509  Tree t = parser.parse_in_arena("myfile.yml", "foo: bar");
1510  assert(parser.location(t["foo"]).line == 0u);
1511  @endcode
1512  - Locations are disabled by default:
1513  @code{c++}
1514  Parser parser;
1515  assert(parser.options().locations() == false);
1516  @endcode
1517 - Deprecate `Tree::arena_pos()`: use `Tree::arena_size()` instead ([PR#290](https://github.com/biojppm/rapidyaml/pull/290)).
1518 - Deprecate pointless `has_siblings()`: use `Tree::has_other_siblings()` instead ([PR#330](https://github.com/biojppm/rapidyaml/pull/330).
1519 
1520 
1521 ### Performance improvements
1522 
1523 - Improve performance of integer serialization and deserialization (in [c4core](https://github.com/biojppm/c4core)). Eg, on Linux/g++11.2, with integral types:
1524  - `c4::to_chars()` can be expected to be roughly...
1525  - ~40% to 2x faster than `std::to_chars()`
1526  - ~10x-30x faster than `sprintf()`
1527  - ~50x-100x faster than a naive `stringstream::operator<<()` followed by `stringstream::str()`
1528  - `c4::from_chars()` can be expected to be roughly...
1529  - ~10%-30% faster than `std::from_chars()`
1530  - ~10x faster than `scanf()`
1531  - ~30x-50x faster than a naive `stringstream::str()` followed by `stringstream::operator>>()`
1532  For more details, see [the changelog for c4core 0.1.10](https://github.com/biojppm/c4core/releases/tag/v0.1.10).
1533 - Fix [#289](https://github.com/biojppm/rapidyaml/issues/289) and [#331](https://github.com/biojppm/rapidyaml/issues/331) - parsing of single-line flow-style sequences had quadratic complexity, causing long parse times in ultra long lines [PR#293](https://github.com/biojppm/rapidyaml/pull/293)/[PR#332](https://github.com/biojppm/rapidyaml/pull/332).
1534  - This was due to scanning for the token `: ` before scanning for `,` or `]`, which caused line-length scans on every scalar scan. Changing the order of the checks was enough to address the quadratic complexity, and the parse times for flow-style are now in line with block-style.
1535  - As part of this changeset, a significant number of runtime branches was eliminated by separating `Parser::_scan_scalar()` into several different `{seq,map}x{block,flow}` functions specific for each context. Expect some improvement in parse times.
1536  - Also, on Debug builds (or assertion-enabled builds) there was a paranoid assertion calling `Tree::has_child()` in `Tree::insert_child()` that caused quadratic behavior because the assertion had linear complexity. It was replaced with a somewhat equivalent O(1) assertion.
1537  - Now the byte throughput is independent of line size for styles and containers. This can be seen in the table below, which shows parse troughputs in MB/s of 1000 containers of different styles and sizes (flow containers are in a single line):
1538 
1539  | Container | Style | 10elms | 100elms | 1000elms |
1540  |-----------|-------|-------------|--------------|---------------|
1541  | 1000 Maps | block | 50.8MB/s | 57.8MB/s | 63.9MB/s |
1542  | 1000 Maps | flow | 58.2MB/s | 65.9MB/s | 74.5MB/s |
1543  | 1000 Seqs | block | 55.7MB/s | 59.2MB/s | 60.0MB/s |
1544  | 1000 Seqs | flow | 52.8MB/s | 55.6MB/s | 54.5MB/s |
1545 - Fix [#329](https://github.com/biojppm/rapidyaml/issues/329): complexity of `has_sibling()` and `has_child()` is now O(1), previously was linear ([PR#330](https://github.com/biojppm/rapidyaml/pull/330)).
1546 
1547 
1548 ### Fixes
1549 
1550 - Fix [#233](https://github.com/biojppm/rapidyaml/issues/233) - accept leading colon in the first key of a flow map (`UNK` node) [PR#234](https://github.com/biojppm/rapidyaml/pull/234):
1551  @code{yaml}
1552  :foo: # parse error on the leading colon
1553  :bar: a # parse error on the leading colon
1554  :barbar: b # was ok
1555  :barbarbar: c # was ok
1556  foo: # was ok
1557  bar: a # was ok
1558  :barbar: b # was ok
1559  :barbarbar: c # was ol
1560  @endcode
1561 - Fix [#253](https://github.com/biojppm/rapidyaml/issues/253): double-quoted emitter should encode carriage-return `\r` to preserve roundtrip equivalence:
1562  @code{c++}
1563  Tree tree;
1564  NodeRef root = tree.rootref();
1565  root |= MAP;
1566  root["s"] = "t\rt";
1567  root["s"] |= _WIP_VAL_DQUO;
1568  std::string s = emitrs<std::string>(tree);
1569  EXPECT_EQ(s, "s: \"t\\rt\"\n");
1570  Tree tree2 = parse_in_arena(to_csubstr(s));
1571  EXPECT_EQ(tree2["s"].val(), tree["s"].val());
1572  @endcode
1573 - Fix parsing of empty block folded+literal scalars when they are the last child of a container (part of [PR#264](https://github.com/biojppm/rapidyaml/issues/264)):
1574  @code{yaml}
1575  seq:
1576  - ""
1577  - ''
1578  - >
1579  - | # error, the resulting val included all the YAML from the next node
1580  seq2:
1581  - ""
1582  - ''
1583  - |
1584  - > # error, the resulting val included all the YAML from the next node
1585  map:
1586  a: ""
1587  b: ''
1588  c: >
1589  d: | # error, the resulting val included all the YAML from the next node
1590  map2:
1591  a: ""
1592  b: ''
1593  c: |
1594  d: > # error, the resulting val included all the YAML from the next node
1595  lastly: the last
1596  @endcode
1597 - Fix [#274](https://github.com/biojppm/rapidyaml/issues/274) ([PR#296](https://github.com/biojppm/rapidyaml/pull/296)): Lists with unindented items and trailing empty values parse incorrectly:
1598  @code{yaml}
1599  foo:
1600  - bar
1601  -
1602  baz: qux
1603  @endcode
1604  was wrongly parsed as
1605  @code{yaml}
1606  foo:
1607  - bar
1608  - baz: qux
1609  @endcode
1610 - Fix [#277](https://github.com/biojppm/rapidyaml/issues/277) ([PR#340](https://github.com/biojppm/rapidyaml/pull/340)): merge fails with duplicate keys.
1611 - Fix [#337](https://github.com/biojppm/rapidyaml/issues/337) ([PR#338](https://github.com/biojppm/rapidyaml/pull/338)): empty lines in block scalars shall not have tab characters `\t`.
1612 - Fix [#268](https://github.com/biojppm/rapidyaml/issues/268) ([PR#339](https://github.com/biojppm/rapidyaml/pull/339)): don't override key type_bits when copying val. This was causing problematic resolution of anchors/references.
1613 - Fix [#309](https://github.com/biojppm/rapidyaml/issues/309) ([PR#310](https://github.com/biojppm/rapidyaml/pull/310)): emitted scalars containing `@` or `` ` `` should be quoted.
1614  - The quotes should be added only when they lead the scalar. See [#320](https://github.com/biojppm/rapidyaml/issues/320) and [PR#334](https://github.com/biojppm/rapidyaml/pull/334).
1615 - Fix [#297](https://github.com/biojppm/rapidyaml/issues/297) ([PR#298](https://github.com/biojppm/rapidyaml/pull/298)): JSON emitter should escape control characters.
1616 - Fix [#292](https://github.com/biojppm/rapidyaml/issues/292) ([PR#299](https://github.com/biojppm/rapidyaml/pull/299)): JSON emitter should quote version string scalars like `0.1.2`.
1617 - Fix [#291](https://github.com/biojppm/rapidyaml/issues/291) ([PR#299](https://github.com/biojppm/rapidyaml/pull/299)): JSON emitter should quote scalars with leading zero, eg `048`.
1618 - Fix [#280](https://github.com/biojppm/rapidyaml/issues/280) ([PR#281](https://github.com/biojppm/rapidyaml/pull/281)): deserialization of `std::vector<bool>` failed because its `operator[]` returns a `reference` instead of `value_type`.
1619 - Fix [#288](https://github.com/biojppm/rapidyaml/issues/288) ([PR#290](https://github.com/biojppm/rapidyaml/pull/290)): segfault on successive calls to `Tree::_grow_arena()`, caused by using the arena position instead of its length as starting point for the new arena capacity.
1620 - Fix [#324](https://github.com/biojppm/rapidyaml/issues/324) ([PR#328](https://github.com/biojppm/rapidyaml/pull/328)): eager assertion prevented moving nodes to the first position in a parent.
1621 - Fix `Tree::_clear_val()`: was clearing key instead ([PR#335](https://github.com/biojppm/rapidyaml/pull/335)).
1622 - YAML test suite events emitter: fix emission of inheriting nodes. The events for `{<<: *anchor, foo: bar}` are now correctly emitted as:
1623  @code{yaml}
1624  =VAL :<< # previously was =ALI <<
1625  =ALI *anchor
1626  =VAL :foo
1627  =VAL :bar
1628  @endcode
1629 - Fix [#246](https://github.com/biojppm/rapidyaml/issues/246): add missing `#define` for the include guard of the amalgamated header.
1630 - Fix [#326](https://github.com/biojppm/rapidyaml/issues/326): honor runtime settings for calling debugbreak, add option to disable any calls to debugbreak.
1631 - Fix [cmake#8](https://github.com/biojppm/cmake/issues/8): `SOVERSION` missing from shared libraries.
1632 
1633 
1634 ### Python
1635 
1636 - The Python packages for Windows and MacOSX are causing problems in the CI, and were mostly disabled. The problematic packages are successfully made, but then fail to be imported. This was impossible to reproduce outside of the CI, and they were disabled since they were delaying the release. As a consequence, the Python release will have very limited compiled packages for Windows (only Python 3.6 and 3.7) or MacOSX. Help would be appreciated from those interested in these packages.
1637 
1638 
1639 ### Thanks
1640 
1641 - [\@NaN-git](https://github.com/NaN-git)
1642 - [\@dancingbug](https://github.com/dancingbug)
1643 
1644 
1645 ---------------------------------------
1646 <a name="v0.4.1"></a>
1647 ## 0.4.1
1648 [Github release: 0.4.1](https://github.com/biojppm/rapidyaml/releases/tag/v0.4.1)
1649 
1650 ### Fixes
1651 
1652 - Fix [#223](https://github.com/biojppm/rapidyaml/issues/223): assertion peeking into the last line when it was whitespaces only.
1653 
1654 
1655 ---------------------------------------
1656 <a name="v0.4.0"></a>
1657 ## 0.4.0
1658 [Github release: 0.4.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.4.0)
1659 
1660 This release improves compliance with the [YAML test suite](https://github.com/yaml/yaml-test-suite/) (thanks [\@ingydotnet](https://github.com/ingydotnet) and [\@perlpunk](https://github.com/perlpunk) for extensive and helpful cooperation), and adds node location tracking using the parser.
1661 
1662 
1663 ### Breaking changes
1664 
1665 As part of the [new feature to track source locations](https://github.com/biojppm/rapidyaml/pull/168), opportunity was taken to address a number of pre-existing API issues. These changes consisted of:
1666 
1667 - Deprecate `c4::yml::parse()` and `c4::yml::Parser::parse()` overloads; all these functions will be removed in short order. Until removal, any call from client code will trigger a compiler warning.
1668 - Add `parse()` alternatives, either `parse_in_place()` or `parse_in_arena()`:
1669  - `parse_in_place()` receives only `substr` buffers, ie mutable YAML source buffers. Trying to pass a `csubstr` buffer to `parse_in_place()` will cause a compile error:
1670  @code{c++}
1671  substr readwrite = /*...*/;
1672  Tree tree = parse_in_place(readwrite); // OK
1673 
1674  csubstr readonly = /*...*/;
1675  Tree tree = parse_in_place(readonly); // compile error
1676  @endcode
1677  - `parse_in_arena()` receives only `csubstr` buffers, ie immutable YAML source buffers. Prior to parsing, the buffer is copied to the tree's arena, then the copy is parsed in place. Because `parse_in_arena()` is meant for immutable buffers, overloads receiving a `substr` YAML buffer are now declared but marked deprecated, and intentionally left undefined, such that calling `parse_in_arena()` with a `substr` will cause a linker error as well as a compiler warning.
1678  @code{c++}
1679  substr readwrite = /*...*/;
1680  Tree tree = parse_in_arena(readwrite); // compile warning+linker error
1681  @endcode
1682  This is to prevent an accidental extra copy of the mutable source buffer to the tree's arena: `substr` is implicitly convertible to `csubstr`. If you really intend to parse an originally mutable buffer in the tree's arena, convert it first explicitly to immutable by assigning the `substr` to a `csubstr` prior to calling `parse_in_arena()`:
1683  @code{c++}
1684  substr readwrite = /*...*/;
1685  csubstr readonly = readwrite; // ok
1686  Tree tree = parse_in_arena(readonly); // ok
1687  @endcode
1688  This problem does not occur with `parse_in_place()` because `csubstr` is not implicitly convertible to `substr`.
1689 - In the python API, `ryml.parse()` was removed and not just deprecated; the `parse_in_arena()` and `parse_in_place()` now replace this.
1690 - `Callbacks`: changed behavior in `Parser` and `Tree`:
1691  - When a tree is copy-constructed or move-constructed to another, the receiving tree will start with the callbacks of the original.
1692  - When a tree is copy-assigned or move-assigned to another, the receiving tree will now change its callbacks to the original.
1693  - When a parser creates a new tree, the tree will now use a copy of the parser's callbacks object.
1694  - When an existing tree is given directly to the parser, both the tree and the parser now retain their own callback objects; any allocation or error during parsing will go through the respective callback object.
1695 
1696 
1697 ### New features
1698 
1699 - Add tracking of source code locations. This is useful for reporting semantic errors after the parsing phase (ie where the YAML is syntatically valid and parsing is successful, but the tree contents are semantically invalid). The locations can be obtained lazily from the parser when the first location is queried:
1700  @code{c++}
1701  // To obtain locations, use of the parser is needed:
1702  ryml::Parser parser;
1703  ryml::Tree tree = parser.parse_in_arena("source.yml", R"({
1704  aa: contents,
1705  foo: [one, [two, three]]
1706  })");
1707  // After parsing, on the first call to obtain a location,
1708  // the parser will cache a lookup structure to accelerate
1709  // tracking the location of a node, with complexity
1710  // O(numchars(srcbuffer)). Then it will do the lookup, with
1711  // complexity O(log(numlines(srcbuffer))).
1712  ryml::Location loc = parser.location(tree.rootref());
1713  assert(parser.location_contents(loc).begins_with("{"));
1714  // note the location members are zero-based:
1715  assert(loc.offset == 0u);
1716  assert(loc.line == 0u);
1717  assert(loc.col == 0u);
1718  // On the next call to location(), the accelerator is reused
1719  // and only the lookup is done.
1720  loc = parser.location(tree["aa"]);
1721  assert(parser.location_contents(loc).begins_with("aa"));
1722  assert(loc.offset == 2u);
1723  assert(loc.line == 1u);
1724  assert(loc.col == 0u);
1725  // KEYSEQ in flow style: points at the key
1726  loc = parser.location(tree["foo"]);
1727  assert(parser.location_contents(loc).begins_with("foo"));
1728  assert(loc.offset == 16u);
1729  assert(loc.line == 2u);
1730  assert(loc.col == 0u);
1731  loc = parser.location(tree["foo"][0]);
1732  assert(parser.location_contents(loc).begins_with("one"));
1733  assert(loc.line == 2u);
1734  assert(loc.col == 6u);
1735  // SEQ in flow style: location points at the opening '[' (there's no key)
1736  loc = parser.location(tree["foo"][1]);
1737  assert(parser.location_contents(loc).begins_with("["));
1738  assert(loc.line == 2u);
1739  assert(loc.col == 11u);
1740  loc = parser.location(tree["foo"][1][0]);
1741  assert(parser.location_contents(loc).begins_with("two"));
1742  assert(loc.line == 2u);
1743  assert(loc.col == 12u);
1744  loc = parser.location(tree["foo"][1][1]);
1745  assert(parser.location_contents(loc).begins_with("three"));
1746  assert(loc.line == 2u);
1747  assert(loc.col == 17u);
1748  // NOTE: reusing the parser with a new YAML source buffer
1749  // will invalidate the accelerator.
1750  @endcode
1751  See more details in the [quickstart sample](https://github.com/biojppm/rapidyaml/blob/bfb073265abf8c58bbeeeed7fb43270e9205c71c/samples/quickstart.cpp#L3759). Thanks to [\@cschreib](https://github.com/cschreib) for submitting a working example proving how simple it could be to achieve this.
1752 - `Parser`:
1753  - add `source()` and `filename()` to get the latest buffer and filename to be parsed
1754  - add `callbacks()` to get the parser's callbacks
1755 - Add `from_tag_long()` and `normalize_tag_long()`:
1756  @code{c++}
1757  assert(from_tag_long(TAG_MAP) == "<tag:yaml.org,2002:map>");
1758  assert(normalize_tag_long("!!map") == "<tag:yaml.org,2002:map>");
1759  @endcode
1760 - Add an experimental API to resolve tags based on the tree's tag directives. This API is still imature and will likely be subject to changes, so we won't document it yet.
1761 - Regarding emit styles (see issue [#37](https://github.com/biojppm/rapidyaml/issues/37)): add an experimental API to force flow/block style on container nodes, as well as block-literal/block-folded/double-quoted/single-quoted/plain styles on scalar nodes. This API is also immature and will likely be subject to changes, so we won't document it yet. But if you are desperate for this functionality, the new facilities will let you go further.
1762 - Add preliminary support for bare-metal ARM architectures, with CI tests pending implementation of QEMU action. ([#193](https://github.com/biojppm/rapidyaml/issues/193), [c4core#63](https://github.com/biojppm/c4core/issues/63)).
1763 - Add preliminary support for RISC-V architectures, with CI tests pending availability of RISC-V based github actions. ([c4core#69](https://github.com/biojppm/c4core/pulls/69)).
1764 
1765 
1766 ### Fixes
1767 
1768 - Fix edge cases of parsing of explicit keys (ie keys after `?`) ([PR#212](https://github.com/biojppm/rapidyaml/pulls/212)):
1769  @code{yaml}
1770  # all these were fixed:
1771  ? : # empty
1772  ? explicit key # this comment was not parsed correctly
1773  ? # trailing empty key was not added to the map
1774  @endcode
1775 - Fixed parsing of tabs used as whitespace tokens after `:` or `-`. This feature [is costly (see some benchmark results here)](https://github.com/biojppm/rapidyaml/pull/211#issuecomment-1030688035) and thus it is disabled by default, and requires defining a macro or cmake option `RYML_WITH_TAB_TOKENS` to enable ([PR#211](https://github.com/biojppm/rapidyaml/pulls/211)).
1776 - Allow tab indentation in flow seqs ([PR#215](https://github.com/biojppm/rapidyaml/pulls/215)) (6CA3).
1777 - ryml now parses successfully compact JSON code `{"like":"this"}` without any need for preprocessing. This code was not valid YAML 1.1, but was made valid in YAML 1.2. So the `preprocess_json()` functions, used to insert spaces after `:` are no longer necessary and have been removed. If you were using these functions, remove the calls and just pass the original source directly to ryml's parser ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)).
1778 - Fix handling of indentation when parsing block scalars ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)):
1779  @code{yaml}
1780  ---
1781  |
1782  hello
1783  there
1784  ---
1785  |
1786  ciao
1787  qua
1788  ---
1789  - |
1790  hello
1791  there
1792  - |
1793  ciao
1794  qua
1795  ---
1796  foo: |
1797  hello
1798  there
1799  bar: |
1800  ciao
1801  qua
1802  @endcode
1803 - Fix parsing of maps when opening a scope with whitespace before the colon ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)):
1804  @code{yaml}
1805  foo0 : bar
1806  ---
1807  foo1 : bar # the " :" was causing an assert
1808  ---
1809  foo2 : bar
1810  ---
1811  foo3 : bar
1812  ---
1813  foo4 : bar
1814  @endcode
1815 - Ensure container keys preserve quote flags when the key is quoted ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)).
1816 - Ensure scalars beginning with `%` are emitted with quotes (([PR#216](https://github.com/biojppm/rapidyaml/pulls/216)).
1817 - Fix [#203](https://github.com/biojppm/rapidyaml/issues/203): when parsing, do not convert `null` or `~` to null scalar strings. Now the scalar strings contain the verbatim contents of the original scalar; to query whether a scalar value is null, use `Tree::key_is_null()/val_is_null()` and `NodeRef::key_is_null()/val_is_null()` which return true if it is empty or any of the unquoted strings `~`, `null`, `Null`, or `NULL`. ([PR#207](https://github.com/biojppm/rapidyaml/pulls/207)):
1818 - Fix [#205](https://github.com/biojppm/rapidyaml/issues/205): fix parsing of escaped characters in double-quoted strings: \c `"\\\"\n\r\t<TAB>\/<SPC>\0\b\f\a\v\e\_\N\L\P"` ([PR#207](https://github.com/biojppm/rapidyaml/pulls/207)).
1819 - Fix [#204](https://github.com/biojppm/rapidyaml/issues/204): add decoding of unicode codepoints \c "\x" \c "\u" \c "\U" in double-quoted scalars:
1820  @code{c++}
1821  Tree tree = parse_in_arena(R"(["\u263A \xE2\x98\xBA \u2705 \U0001D11E"])");
1822  assert(tree[0].val() == "☺ ☺ ✅ 𝄞");
1823  @endcode
1824  This is mandated by the YAML standard and was missing from ryml ([PR#207](https://github.com/biojppm/rapidyaml/pulls/207)).
1825 - Fix emission of nested nodes which are sequences: when these are given as the emit root, the `- ` from the parent node was added ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)):
1826  @code{c++}
1827  const ryml::Tree tree = ryml::parse_in_arena(R"(
1828  - - Rochefort 10
1829  - Busch
1830  - Leffe Rituel
1831  - - and so
1832  - many other
1833  - wonderful beers
1834  )");
1835  // before (error), YAML valid but not expected
1836  //assert(ryml::emitrs<std::string>(tree[0][3]) == R"(- - and so
1837  // - many other
1838  // - wonderful beers
1839  //)");
1840  // now: YAML valid and expected
1841  assert(ryml::emitrs<std::string>(tree[0][3]) == R"(- and so
1842  - many other
1843  - wonderful beers
1844  )");
1845  @endcode
1846 - Fix parsing of isolated `!`: should be an empty val tagged with `!` (UKK06-02) ([PR#215](https://github.com/biojppm/rapidyaml/pulls/215)).
1847 - Fix [#193](https://github.com/biojppm/rapidyaml/issues/193): amalgamated header missing `\#include <stdarg.h>` which prevented compilation in bare-metal `arm-none-eabi` ([PR #195](https://github.com/biojppm/rapidyaml/pull/195), requiring also [c4core #64](https://github.com/biojppm/c4core/pull/64)).
1848 - Accept `infinity`,`inf` and `nan` as special float values (but not mixed case: eg `InFiNiTy` or `Inf` or `NaN` are not accepted) ([PR #186](https://github.com/biojppm/rapidyaml/pull/186)).
1849 - Accept special float values with upper or mixed case: `.Inf`, `.INF`, `.NaN`, `.NAN`. Previously, only low-case `.inf` and `.nan` were accepted ([PR #186](https://github.com/biojppm/rapidyaml/pull/186)).
1850 - Accept `null` with upper or mixed case: `Null` or `NULL`. Previously, only low-case `null` was accepted ([PR #186](https://github.com/biojppm/rapidyaml/pull/186)).
1851 - Fix [#182](https://github.com/biojppm/rapidyaml/issues/182): add missing export of DLL symbols, and document requirements for compiling shared library from the amalgamated header. [PR #183](https://github.com/biojppm/rapidyaml/pull/183), also [PR c4core#56](https://github.com/biojppm/c4core/pull/56) and [PR c4core#57](https://github.com/biojppm/c4core/pull/57).
1852 - Fix [#185](https://github.com/biojppm/rapidyaml/issues/185): compilation failures in earlier Xcode versions ([PR #187](https://github.com/biojppm/rapidyaml/pull/187) and [PR c4core#61](https://github.com/biojppm/c4core/pull/61)):
1853  - `c4/substr_fwd.hpp`: (failure in Xcode 12 and earlier) forward declaration for `std::allocator` is inside the `inline namespace __1`, unlike later versions.
1854  - `c4/error.hpp`: (failure in debug mode in Xcode 11 and earlier) `__clang_major__` does not mean the same as in the common clang, and as a result the warning `-Wgnu-inline-cpp-without-extern` does not exist there.
1855 - Ensure error messages do not wrap around the buffer when the YAML source line is too long ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)).
1856 - Ensure error is emitted on unclosed flow sequence characters eg `[[[` ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)). Same thing for `[]]`.
1857 - Refactor error message building and parser debug logging to use the new dump facilities in c4core ([PR#212](https://github.com/biojppm/rapidyaml/pulls/212)).
1858 - Parse: fix read-after-free when duplicating a parser state node, when pushing to the stack requires a stack buffer resize ([PR#210](https://github.com/biojppm/rapidyaml/pulls/210)).
1859 - Add support for legacy gcc 4.8 ([PR#217](https://github.com/biojppm/rapidyaml/pulls/217)).
1860 
1861 
1862 ### Improvements
1863 
1864 - Rewrite filtering of scalars to improve parsing performance ([PR #188](https://github.com/biojppm/rapidyaml/pull/188)). Previously the scalar strings were filtered in place, which resulted in quadratic complexity in terms of scalar length. This did not matter for small scalars fitting the cache (which is the more frequent case), but grew in cost as the scalars grew larger. To achieve linearity, the code was changed so that the strings are now filtered to a temporary scratch space in the parser, and copied back to the output buffer after filtering, if any change occurred. The improvements were large for the folded scalars; the table below shows the benchmark results of throughput (MB/s) for several files containing large scalars of a single type:
1865  | scalar type | before | after | improvement |
1866  |:------------|-------:|-------:|---------:|
1867  | block folded | 276 | 561 | 103% |
1868  | block literal | 331 | 611 | 85% |
1869  | single quoted | 247 | 267 | 8% |
1870  | double quoted | 212 | 230 | 8% |
1871  | plain (unquoted) | 173 | 186 | 8% |
1872 
1873  The cost for small scalars is negligible, with benchmark improvement in the interval of -2% to 5%, so well within the margin of benchmark variability in a regular OS. In the future, this will be optimized again by copying each character in place, thus completely avoiding the staging arena.
1874 - `Callbacks`: add `operator==()` and `operator!=()` ([PR #168](https://github.com/biojppm/rapidyaml/pull/168)).
1875 - `Tree`: on error or assert prefer the error callback stored into the tree's current `Callbacks`, rather than the global `Callbacks` ([PR #168](https://github.com/biojppm/rapidyaml/pull/168)).
1876 - `detail::stack<>`: improve behavior when assigning from objects `Callbacks`, test all rule-of-5 scenarios ([PR #168](https://github.com/biojppm/rapidyaml/pull/168)).
1877 - Improve formatting of error messages.
1878 
1879 
1880 ### Thanks
1881 
1882 - [\@ingydotnet](https://github.com/ingydotnet
1883 - [\@perlpunk](https://github.com/perlpunk)
1884 - [\@cschreib](https://github.com/cschreib)
1885 - [\@fargies](https://github.com/fargies)
1886 - [\@Xeonacid](https://github.com/Xeonacid)
1887 - [\@aviktorov](https://github.com/aviktorov)
1888 - [\@xTVaser](https://github.com/xTVaser)
1889 
1890 
1891 ---------------------------------------
1892 <a name="v0.3.0"></a>
1893 ## 0.3.0
1894 [Github release: 0.3.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.3.0)
1895 
1896 ### Breaking changes
1897 
1898 Despite ryml being still in a non-stable 0.x.y version, considerable effort goes into trying to avoid breaking changes. However, this release has to collect on the [semantic versioning](https://semver.org/) prerogative for breaking changes. This is a needed improvement, so sorry for any nuisance!
1899 
1900 **The allocation and error callback logic was revamped** on the [amalgamation PR](https://github.com/biojppm/rapidyaml/pull/172). Now trees and parsers receive (and store) a full `ryml::Callbacks` object instead of the (now removed) `ryml::Allocator` which had a pointer to a (now removed) `ryml::MemoryResourceCallbacks`, which was a (now removed) `ryml::MemoryResource`. To be clear, the `Callbacks` class is unchanged, other than removing some unneeded helper methods.
1901 
1902 These changes were motivated by unfortunate name clashes between `c4::Allocator/ryml::Allocator` and `c4::MemoryResource/ryml::MemoryResource`, occurring if `<c4/allocator.hpp>` or `<c4/memory_resource.hpp>` were included before `<c4/yml/common.hpp>`. They also significantly simplify this part of the API, making it really easier to understand.
1903 
1904 As a consequence of the above changes, the global memory resource getters and setters for ryml were also removed: `ryml::get_memory_resource()/ryml::set_memory_resource()`.
1905 
1906 Here's an example of the required changes in client code. First the old client code (from the quickstart):
1907 
1908 @code{c++}
1909 struct PerTreeMemoryExample : public ryml::MemoryResource
1910 {
1911  void *allocate(size_t len, void * hint) override;
1912  void free(void *mem, size_t len) override;
1913 };
1914 
1915 PerTreeMemoryExample mrp;
1916 PerTreeMemoryExample mr1;
1917 PerTreeMemoryExample mr2;
1918 
1919 ryml::Parser parser = {ryml::Allocator(&mrp)};
1920 ryml::Tree tree1 = {ryml::Allocator(&mr1)};
1921 ryml::Tree tree2 = {ryml::Allocator(&mr2)};
1922 @endcode
1923 
1924 Should now be rewritten to:
1925 
1926 @code{c++}
1927 struct PerTreeMemoryExample
1928 {
1929  ryml::Callbacks callbacks() const; // helper to create the callbacks
1930 };
1931 
1932 PerTreeMemoryExample mrp;
1933 PerTreeMemoryExample mr1;
1934 PerTreeMemoryExample mr2;
1935 
1936 ryml::Parser parser = {mrp.callbacks()};
1937 ryml::Tree tree1 = {mr1.callbacks()};
1938 ryml::Tree tree2 = {mr2.callbacks()};
1939 @endcode
1940 
1941 
1942 ### New features
1943 - Add amalgamation into a single header file ([PR #172](https://github.com/biojppm/rapidyaml/pull/172)):
1944  - The amalgamated header will be available together with the deliverables from each release.
1945  - To generate the amalgamated header:
1946  @code
1947  $ python tools/amalgamate.py ryml_all.hpp
1948  @encode
1949  - To use the amalgamated header:
1950  - Include at will in any header of your project.
1951  - In one - and only one - of your project source files, `#define RYML_SINGLE_HDR_DEFINE_NOW` and then `#include <ryml_all.hpp>`. This will enable the function and class definitions in the header file. For example, here's a sample program:
1952  @code{c++}
1953  #include <iostream>
1954  #define RYML_SINGLE_HDR_DEFINE_NOW // do this before the include
1955  #include <ryml_all.hpp>
1956  int main()
1957  {
1958  auto tree = ryml::parse("{foo: bar}");
1959  std::cout << tree["foo"].val() << "\n";
1960  }
1961  @endcode
1962 - Add `Tree::change_type()` and `NodeRef::change_type()` ([PR #171](https://github.com/biojppm/rapidyaml/pull/171)):
1963  @code{c++}
1964  // clears a node and sets its type to a different type (one of `VAL`, `SEQ`, `MAP`):
1965  Tree t = parse("{keyval0: val0, keyval1: val1, keyval2: val2}");
1966  t[0].change_type(VAL);
1967  t[1].change_type(MAP);
1968  t[2].change_type(SEQ);
1969  Tree expected = parse("{keyval0: val0, keyval1: {}, keyval2: []}");
1970  assert(emitrs<std::string>(t) == emitrs<std::string>(expected));
1971  @endcode
1972 - Add support for compilation with emscripten (WebAssembly+javascript) ([PR #176](https://github.com/biojppm/rapidyaml/pull/176)).
1973 
1974 ### Fixes
1975 
1976 - Take block literal indentation as relative to current indentation level, rather than as an absolute indentation level ([PR #178](https://github.com/biojppm/rapidyaml/pull/178)):
1977  @code{yaml}
1978  foo:
1979  - |
1980  child0
1981  - |2
1982  child2 # indentation is 4, not 2
1983  @endcode
1984 - Fix parsing when seq member maps start without a key ([PR #178](https://github.com/biojppm/rapidyaml/pull/178)):
1985  @code{yaml}
1986  # previously this resulted in a parse error
1987  - - : empty key
1988  - - : another empty key
1989  @endcode
1990 - Prefer passing `substr` and `csubstr` by value instead of const reference ([PR #171](https://github.com/biojppm/rapidyaml/pull/171))
1991 - Fix [#173](https://github.com/biojppm/rapidyaml/issues/173): add alias target `ryml::ryml` ([PR #174](https://github.com/biojppm/rapidyaml/pull/174))
1992 - Speedup compilation of tests by removing linking with yaml-cpp and libyaml. ([PR #177](https://github.com/biojppm/rapidyaml/pull/177))
1993 - Fix [c4core#53](https://github.com/biojppm/c4core/issues/53): cmake install targets were missing call to `export()` ([PR #179](https://github.com/biojppm/c4core/pull/179)).
1994 - Add missing export to `Tree` ([PR #181](https://github.com/biojppm/c4core/pull/181)).
1995 
1996 
1997 ### Thanks
1998 
1999 - [\@aviktorov](https://github.com/aviktorov)
2000 
2001 
2002 
2003 ---------------------------------------
2004 <a name="v0.2.3"></a>
2005 ## 0.2.3
2006 [Github release: 0.2.3](https://github.com/biojppm/rapidyaml/releases/tag/v0.2.3)
2007 
2008 This release is focused on bug fixes and compliance with the [YAML test suite](https://github.com/yaml/yaml-test-suite).
2009 
2010 ### New features
2011 - Add support for CPU architectures aarch64, ppc64le, s390x.
2012 - Update c4core to [0.1.7](https://github.com/biojppm/c4core/releases/tag/v0.1.7)
2013 - `Tree` and `NodeRef`: add document getter `doc()` and `docref()`
2014  @code{c++}
2015  Tree tree = parse(R"(---
2016  doc0
2017  ---
2018  doc1
2019  )");
2020  NodeRef stream = t.rootref();
2021  assert(stream.is_stream());
2022  // tree.doc(i): get the index of the i-th doc node.
2023  // Equivalent to tree.child(tree.root_id(), i)
2024  assert(tree.doc(0) == 1u);
2025  assert(tree.doc(1) == 2u);
2026  // tree.docref(i), same as above, return NodeRef
2027  assert(tree.docref(0).val() == "doc0");
2028  assert(tree.docref(1).val() == "doc1");
2029  // stream.doc(i), same as above, given NodeRef
2030  assert(stream.doc(0).val() == "doc0");
2031  assert(stream.doc(1).val() == "doc1");
2032  @endcode
2033 
2034 ### Fixes
2035 
2036 - Fix compilation with `C4CORE_NO_FAST_FLOAT` ([PR #163](https://github.com/biojppm/rapidyaml/pull/163))
2037 
2038 #### Flow maps
2039 
2040 - Fix parse of multiline plain scalars inside flow maps ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2041  @code{yaml}
2042  # test case UT92
2043  # all parsed as "matches %": 20
2044  - { matches
2045  % : 20 }
2046  - { matches
2047  %: 20 }
2048  - { matches
2049  %:
2050  20 }
2051  @endcode
2052 
2053 
2054 #### Tags
2055 
2056 - Fix parsing of tags followed by comments in sequences ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2057  @code{yaml}
2058  # test case 735Y
2059  - !!map # Block collection
2060  foo : bar
2061  @endcode
2062 
2063 #### Quoted scalars
2064 - Fix filtering of tab characters in quoted scalars ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2065  @code{yaml}
2066  ---
2067  # test case 5GBF
2068  "Empty line
2069  <TAB>
2070  as a line feed"
2071  # now correctly parsed as "Empty line\nas a line feed"
2072  ---
2073  # test case PRH3
2074  ' 1st non-empty
2075 
2076  <SPC>2nd non-empty<SPC>
2077  <TAB>3rd non-empty '
2078  # now correctly parsed as " 1st non-empty\n2nd non-empty 3rd non-empty "
2079  @endcode
2080 - Fix filtering of backslash characters in double-quoted scalars ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2081  @code{yaml}
2082  # test cases NP9H, Q8AD
2083  "folded<SPC>
2084  to a space,<TAB>
2085  <SPC>
2086  to a line feed, or <TAB>\
2087  \ <TAB>non-content"
2088  # now correctly parsed as "folded to a space,\nto a line feed, or \t \tnon-content"
2089  @endcode
2090 - Ensure filtering of multiline quoted scalars ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2091  @code{yaml}
2092  # all scalars now correctly parsed as "quoted string",
2093  # both for double and single quotes
2094  ---
2095  "quoted
2096  string"
2097  --- "quoted
2098  string"
2099  ---
2100  - "quoted
2101  string"
2102  ---
2103  - "quoted
2104  string"
2105  ---
2106  "quoted
2107  string": "quoted
2108  string"
2109  ---
2110  "quoted
2111  string": "quoted
2112  string"
2113  @endcode
2114 
2115 
2116 #### Block scalars
2117 - Ensure no newlines are added when emitting block scalars ([PR #161](https://github.com/biojppm/rapidyaml/pull/161))
2118 - Fix parsing of block spec with both chomping and indentation: chomping may come before or after the indentation ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2119  @code{yaml}
2120  # the block scalar specs below now have the same effect.
2121  # test cases: D83L, P2AD
2122  - |2-
2123  explicit indent and chomp
2124  - |-2
2125  chomp and explicit indent
2126  @endcode
2127 - Fix [inference of block indentation](https://yaml.org/spec/1.2.2/#8111-block-indentation-indicator) with leading blank lines ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2128  @code{yaml}
2129  # test cases: 4QFQ, 7T8X
2130  - >
2131 
2132 
2133  # child1
2134  # parsed as "\n\n child1"
2135  --- # test case DWX9
2136  |
2137 
2138 
2139  literal
2140 
2141 
2142  text
2143 
2144  # Comment
2145  # parsed as "\n\nliteral\n \n\ntext\n"
2146  @endcode
2147 - Fix parsing of same-indentation block scalars ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2148  @code{yaml}
2149  # test case W4TN
2150  # all docs have the same value: "%!PS-Adobe-2.0"
2151  --- |
2152  %!PS-Adobe-2.0
2153  ...
2154  --- >
2155  %!PS-Adobe-2.0
2156  ...
2157  --- |
2158  %!PS-Adobe-2.0
2159  ...
2160  --- >
2161  %!PS-Adobe-2.0
2162  ...
2163  --- |
2164  %!PS-Adobe-2.0
2165  --- >
2166  %!PS-Adobe-2.0
2167  --- |
2168  %!PS-Adobe-2.0
2169  --- >
2170  %!PS-Adobe-2.0
2171  @endcode
2172 - Folded block scalars: fix folding of newlines at the border of indented parts ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2173  @code{yaml}
2174  # test case 6VJK
2175  # now correctly parsed as "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n"
2176  >
2177  Sammy Sosa completed another
2178  fine season with great stats.
2179 
2180  63 Home Runs
2181  0.288 Batting Average
2182 
2183  What a year!
2184  ---
2185  # test case MJS9
2186  # now correctly parsed as "foo \n\n \t bar\n\nbaz\n"
2187  >
2188  foo<SPC>
2189  <SPC>
2190  <SPC><TAB><SPC>bar
2191 
2192  baz
2193  @endcode
2194 - Folded block scalars: fix folding of newlines when the indented part is at the begining of the scalar ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2195  @code{yaml}
2196  # test case F6MC
2197  a: >2
2198  more indented
2199  regular
2200  # parsed as a: " more indented\nregular\n"
2201  b: >2
2202 
2203 
2204  more indented
2205  regular
2206  # parsed as b: "\n\n more indented\nregular\n"
2207  @endcode
2208 
2209 #### Plain scalars
2210 - Fix parsing of whitespace within plain scalars ([PR #161](https://github.com/biojppm/rapidyaml/pull/161)):
2211  @code{yaml}
2212  ---
2213  # test case NB6Z
2214  key:
2215  value
2216  with
2217 
2218  tabs
2219  tabs
2220 
2221  foo
2222 
2223  bar
2224  baz
2225 
2226  # is now correctly parsed as "value with\ntabs tabs\nfoo\nbar baz"
2227  ---
2228  # test case 9YRD, EX5H (trailing whitespace)
2229  a
2230  b
2231  c
2232  d
2233 
2234  e
2235  # is now correctly parsed as "a b c d\ne"
2236  @endcode
2237 - Fix parsing of unindented plain scalars at the root level scope ([PR #161](https://github.com/biojppm/rapidyaml/pull/161))
2238  @code{yaml}
2239  --- # this parsed
2240  Bare
2241  scalar
2242  is indented
2243  # was correctly parsed as "Bare scalar is indented"
2244  --- # but this failed to parse successfully:
2245  Bare
2246  scalar
2247  is not indented
2248  # is now correctly parsed as "Bare scalar is not indented"
2249  --- # test case NB6Z
2250  value
2251  with
2252 
2253  tabs
2254  tabs
2255 
2256  foo
2257 
2258  bar
2259  baz
2260 
2261  # now correctly parsed as "value with\ntabs tabs\nfoo\nbar baz"
2262  ---
2263  --- # test cases EXG3, 82AN
2264  ---word1
2265  word2
2266  # now correctly parsed as "---word1 word2"
2267  @endcode
2268 - Fix parsing of comments within plain scalars
2269  @code{yaml}
2270  # test case 7TMG
2271  --- # now correctly parsed as "word1"
2272  word1
2273  # comment
2274  --- # now correctly parsed as [word1, word2]
2275  [ word1
2276  # comment
2277  , word2]
2278  @endcode
2279 
2280 #### Python API
2281 - Add missing node predicates in SWIG API definition ([PR #166](https://github.com/biojppm/rapidyaml/pull/166)):
2282  - `is_anchor_or_ref()`
2283  - `is_key_quoted()`
2284  - `is_val_quoted()`
2285  - `is_quoted()`
2286 
2287 
2288 ### Thanks
2289 
2290 - \@[mbs-c](https://github.com/mbs-c)
2291 - [\@simu](https://github.com/simu)
2292 - [\@QuellaZhang](https://github.com/QuellaZhang)
2293 
2294 
2295 ---------------------------------------
2296 <a name="v0.2.2"></a>
2297 ## 0.2.2
2298 [Github release: 0.2.2](https://github.com/biojppm/rapidyaml/releases/tag/v0.2.2)
2299 
2300 Yank python package 0.2.1, was accidentally created while iterating the PyPI submission from the Github action. This release does not add any change, and is functionally the same as [0.2.1](https://github.com/biojppm/rapidyaml/releases/tag/v0.2.1).
2301 
2302 
2303 ---------------------------------------
2304 <a name="v0.2.1"></a>
2305 ## 0.2.1
2306 [Github release: 0.2.1](https://github.com/biojppm/rapidyaml/releases/tag/v0.2.1)
2307 
2308 This release is focused on bug fixes and compliance with the [YAML test suite](https://github.com/yaml/yaml-test-suite).
2309 
2310 ### Breaking changes
2311 
2312 - Fix parsing behavior of root-level scalars: now these are parsed into a DOCVAL, not SEQ->VAL ([5ba0d56](https://github.com/biojppm/rapidyaml/pull/144/commits/5ba0d56904daef1509f0073695145c4835ab1b30), from [PR #144](https://github.com/biojppm/rapidyaml/pull/144)). Eg,
2313  @code{yaml}
2314  ---
2315  this is a scalar
2316  --- # previously this was parsed as
2317  - this is a scalar
2318  @endcode
2319 - Cleanup type predicate API ([PR #155](https://github.com/biojppm/rapidyaml/pull/155))):
2320  - ensure all type predicates from `Tree` and `NodeRef` forward to the corresponding predicate in `NodeType`
2321  - remove all type predicates and methods from `NodeData`; use the equivalent call from `Tree` or `NodeRef`. For example, for `is_map()`:
2322  @code{c++}
2323  Tree t = parse("{foo: bar}");
2324  size_t map_id = t.root_id();
2325  NodeRef map = t.rootref();
2326  t.get(map_id)->is_map(); // compile error: no longer exists
2327  assert(t.is_map(map_id)); // OK
2328  assert(map.is_map()); // OK
2329  @endcode
2330  - Further cleanup to the type predicate API will be done in the future, especially around the `.has_*()` vs corresponding `.is_*()` naming scheme.
2331 
2332 
2333 ### New features & improvements
2334 
2335 - `Tree::lookup_path_or_modify()`: add overload to graft existing branches ([PR #141](https://github.com/biojppm/rapidyaml/pull/141))
2336 - Callbacks: improve test coverage ([PR #141](https://github.com/biojppm/rapidyaml/pull/141))
2337 - [YAML test suite](https://github.com/yaml/yaml-test-suite) ([PR #144](https://github.com/biojppm/rapidyaml/pull/144), [PR #145](https://github.com/biojppm/rapidyaml/pull/145)): big progress towards compliance with the suite. There are still a number of existing problems, which are the subject of ongoing work. See the [list of current known failures](../test/test_suite/test_suite_parts.cpp) in the test suite file.
2338 - Python wheels and source package are now [uploaded to PyPI](https://pypi.org/project/rapidyaml/) as part of the release process.
2339 
2340 
2341 ### Fixes
2342 
2343 #### Anchors and references
2344 - Fix resolving of nodes with keyref+valref ([PR #144](https://github.com/biojppm/rapidyaml/pull/144)): `{&a a: &b b, *b: *a}`
2345 - Fix parsing of implicit scalars when tags are present ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2346  @code{yaml}
2347  - &a # test case PW8X
2348  - a
2349  - &a : a
2350  b: &b
2351  - &c : &a
2352  - ? &d
2353  - ? &e
2354  : &a
2355  @endcode
2356 - Fix [#151](https://github.com/biojppm/rapidyaml/issues/151): scalars beginning with `*` or `&` or `<<` are now correctly quoted when emitting ([PR #156](https://github.com/biojppm/rapidyaml/pull/156)).
2357 - Also from [PR #156](https://github.com/biojppm/rapidyaml/pull/156), map inheritance nodes like `<<: *anchor` or `<<: [*anchor1, *anchor2]` now have a `KEYREF` flag in their type (until a call to `Tree::resolve()`):
2358  @code{c++}
2359  Tree tree = parse("{map: &anchor {foo: bar}, copy: {<<: *anchor}}");
2360  assert(tree["copy"]["<<"].is_key_ref()); // previously this did not hold
2361  assert(tree["copy"]["<<"].is_val_ref()); // ... but this did
2362  @endcode
2363 
2364 #### Tags
2365 - Fix parsing of tag dense maps and seqs ([PR #144](https://github.com/biojppm/rapidyaml/pull/144)):
2366  @code{yaml}
2367  --- !!map {
2368  k: !!seq [ a, !!str b],
2369  j: !!seq
2370  [ a, !!str b]
2371  --- !!seq [
2372  !!map { !!str k: v},
2373  !!map { !!str ? k: v}
2374  ]
2375  --- !!map
2376  !!str foo: !!map # there was a parse error with the multiple tags
2377  !!int 1: !!float 20.0
2378  !!int 3: !!float 40.0
2379  --- !!seq
2380  - !!map
2381  !!str k1: v1
2382  !!str k2: v2
2383  !!str k3: v3
2384  @endcode
2385 
2386 #### Whitespace
2387 - Fix parsing of double-quoted scalars with tabs ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2388  @code{yaml}
2389  "This has a\ttab"
2390  # is now correctly parsed as "This has a<TAB>tab"
2391  @endcode
2392 - Fix filtering of leading and trailing whitespace within double-quoted scalars ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2393  @code{yaml}
2394  # test case 4ZYM, 7A4E, TL85
2395  "
2396  <SPC><SPC>foo<SPC>
2397  <SPC>
2398  <SPC><TAB><SPC>bar
2399  <SPC><SPC>baz
2400  "
2401  # is now correctly parsed as " foo\nbar\nbaz "
2402  @endcode
2403 - Fix parsing of tabs within YAML tokens ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2404  @code{yaml}
2405  ---<TAB>scalar # test case K54U
2406  ---<TAB>{} # test case Q5MG
2407  --- # test case DC7X
2408  a: b<TAB>
2409  seq:<TAB>
2410  - a<TAB>
2411  c: d<TAB>#X
2412  @endcode
2413 - Fix parsing of flow-style maps with ommitted values without any space ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2414  @code{yaml}
2415  # test case 4ABK
2416  - {foo: , bar: , baz: } # this was parsed correctly as {foo: ~, bar: ~, baz: ~}
2417  - {foo:, bar:, baz:} # ... but this was parsed as {'foo:': , 'bar:': ~, 'baz:': ~}
2418  @endcode
2419 
2420 #### Scalars
2421 - Unescape forward slashes in double quoted string ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2422  @code{yaml}
2423  --- escaped slash: "a\/b" # test case 3UYS
2424  # is now parsed as:
2425  --- escaped slash: "a/b"
2426  @endcode
2427 - Fix filtering of indented regions in folded scalars ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2428  @code{yaml}
2429  # test case 7T8X
2430  - >
2431 
2432  folded
2433  line
2434 
2435  next
2436  line
2437  * bullet
2438 
2439  * list
2440  * lines
2441 
2442  last
2443  line
2444  @endcode
2445  is now correctly parsed as `\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n`.
2446 - Fix parsing of special characters within plain scalars ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2447  @code{yaml}
2448  # test case 3MYT
2449  k:#foo
2450  &a !t s
2451  !t s
2452  # now correctly parsed as "k:#foo &a !t s !t s"
2453  @endcode
2454 - Fix parsing of comments after complex keys ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2455  @code{yaml}
2456  # test case X8DW
2457  ? key
2458  # comment
2459  : value
2460  # now correctly parsed as {key: value}
2461  @endcode
2462 - Fix parsing of consecutive complex keys within maps ([PR #145](https://github.com/biojppm/rapidyaml/pull/145))
2463  @code{yaml}
2464  # test case 7W2P, ZWK4
2465  ? a
2466  ? b
2467  c:
2468  ? d
2469  e:
2470  # now correctly parsed as {a: ~, b: ~, c: ~, d: ~, e: ~}
2471  @endcode
2472 - Fix [#152](https://github.com/biojppm/rapidyaml/issues/152): parse error with folded scalars that are the last in a container ([PR #157](https://github.com/biojppm/rapidyaml/pull/157)):
2473  @code{yaml}
2474  exec:
2475  command:
2476  # before the fix, this folded scalar failed to parse
2477  - |
2478  exec pg_isready -U "dog" -d "dbname=dog" -h 127.0.0.1 -p 5432
2479  parses: no
2480  @endcode
2481 - Fix: documents consisting of a quoted scalar now retain the VALQUO flag ([PR #156](https://github.com/biojppm/rapidyaml/pull/156))
2482  @code{c++}
2483  Tree tree = parse("'this is a quoted scalar'");
2484  assert(tree.rootref().is_doc());
2485  assert(tree.rootref().is_val());
2486  assert(tree.rootref().is_val_quoted());
2487  @endcode
2488 
2489 
2490 #### Document structure
2491 - Empty docs are now parsed as a docval with a null node:
2492  @code{yaml}
2493  --- # test cases 6XDY, 6ZKB, 9BXL, PUW8
2494  ---
2495  ---
2496  @endcode
2497  is now parsed as
2498  @code{yaml}
2499  --- ~
2500  --- ~
2501  --- ~
2502  @endcode
2503 - Prevent creation of DOC nodes from stream-level comments or tags ([PR #145](https://github.com/biojppm/rapidyaml/pull/145)):
2504  @code{yaml}
2505  !foo "bar"
2506  ...
2507  # Global
2508  %TAG ! tag:example.com,2000:app/
2509  ---
2510  !foo "bar"
2511  @endcode
2512  was parsed as
2513  @code{yaml}
2514  ---
2515  !foo "bar"
2516  ---
2517  # notice the empty doc in here
2518  ---
2519  !foo "bar"
2520  @endcode
2521  and it is now correctly parsed as
2522  @code{yaml}
2523  ---
2524  !foo "bar"
2525  ---
2526  !foo "bar"
2527  @endcode
2528  (other than the known limitation that ryml does not do tag lookup).
2529 
2530 
2531 #### General
2532 
2533 - Fix [#147](https://github.com/biojppm/rapidyaml/issues/147): serialize/deserialize special float values `.nan`, `.inf`, `-.inf` ([PR #149](https://github.com/biojppm/rapidyaml/pull/149))
2534 - Fix [#142](https://github.com/biojppm/rapidyaml/issues/142): `preprocess_json()`: ensure quoted ranges are skipped when slurping containers
2535 - Ensure error macros expand to a single statement ([PR #141](https://github.com/biojppm/rapidyaml/pull/141))
2536 - Update c4core to [0.1.4](https://github.com/biojppm/c4core/releases/tag/v0.1.4)
2537 
2538 
2539 ### Special thanks
2540 
2541 - [\@Gei0r](https://github.com/Gei0r)
2542 
2543 
2544 
2545 ---------------------------------------
2546 <a name="v0.2.0"></a>
2547 ## 0.2.0
2548 
2549 [Github release: 0.2.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.2.0)
2550 
2551 ### New features & improvements
2552 - Enable parsing into nested nodes ([87f4184](https://github.com/biojppm/rapidyaml/commit/87f4184))
2553 - `as_json()` can now be called with tree and node id ([4c23041](https://github.com/biojppm/rapidyaml/commit/4c23041))
2554 - Add `Parser::reserve_stack()` ([f31fb9f](https://github.com/biojppm/rapidyaml/commit/f31fb9f))
2555 - Add uninstall target ([PR #122](https://github.com/biojppm/rapidyaml/pull/122))
2556 - Update [c4core](https://github.com/biojppm/c4core) to v0.1.1
2557 - Add a [quickstart sample](samples/quickstart.cpp) with build examples.
2558 - Update README.md to refer to the quickstart
2559 - Add [gdb visualizers](src/ryml-gdbtypes.py)
2560 - Add `SO_VERSION` to shared builds
2561 
2562 ### Fixes
2563 - Fix [#139](https://github.com/biojppm/rapidyaml/issues/139): substr and csubstr not found in ryml namespace
2564 - Fix [#131](https://github.com/biojppm/rapidyaml/issues/131): resolve references to map keys
2565 - Fix [#129](https://github.com/biojppm/rapidyaml/issues/129): quoted strings starting with * parsed as references
2566 - Fix [#128](https://github.com/biojppm/rapidyaml/issues/128): segfault on nonexistent anchor
2567 - Fix [#124](https://github.com/biojppm/rapidyaml/issues/124): parse failure in comments with trailing colon
2568 - Fix [#121](https://github.com/biojppm/rapidyaml/issues/121): preserve quotes when emitting scalars
2569 - Fix [#103](https://github.com/biojppm/rapidyaml/issues/103): ambiguous parsing of null/empty scalars
2570 - Fix [#90](https://github.com/biojppm/rapidyaml/issues/90): CMAKE_CXX_STANDARD ignored
2571 - Fix [#40](https://github.com/biojppm/rapidyaml/issues/40): quadratic complexity from use of `sscanf(%f)`
2572 - Fix emitting json to streams ([dc6af83](https://github.com/biojppm/rapidyaml/commit/dc6af83))
2573 - Set the global memory resource when setting global callbacks ([511cba0](https://github.com/biojppm/rapidyaml/commit/511cba0))
2574 - Fix python packaging ([PR #102](https://github.com/biojppm/rapidyaml/pull/102))
2575 
2576 ### Special thanks
2577 - [\@Gei0r](https://github.com/Gei0r)
2578 - [\@litghost](https://github.com/litghost)
2579 - [\@costashatz](https://github.com/costashatz)
2580 
2581 
2582 ---------------------------------------
2583 <a name="v0.1.0"></a>
2584 ## 0.1.0
2585 [Github release: 0.1.0](https://github.com/biojppm/rapidyaml/releases/tag/v0.1.0)
2586 
2587 This is the first ryml release. Future releases will have a more organized changelog; for now, only recent major changes are listed.
2588 
2589 Please be aware that there are still some anticipated breaking changes in the API before releasing the 1.0 major version. These are highlighted in [the repo ROADMAP](https://github.com/biojppm/rapidyaml/blob/v0.1.0/ROADMAP.md).
2590 
2591 * 2020/October
2592  * [MR#89](https://github.com/biojppm/rapidyaml/pull/89):
2593  * fix python API generation in windows
2594  * use github actions for testing and releasing
2595  * [MR#88](https://github.com/biojppm/rapidyaml/pull/88): [fix MacOS compilation and installs](https://github.com/biojppm/rapidyaml/issues/75). This is a fix from [c4core](https://github.com/biojppm/cmake/issues/1).
2596  * [MR#88](https://github.com/biojppm/rapidyaml/pull/88): [fix boolean handling](https://github.com/biojppm/rapidyaml/issues/74). This is a fix from [c4core](https://github.com/biojppm/c4core/pull/18/). `true` and `false` are now parsed correctly into `bool` variables:
2597  @code{c++}
2598  auto tree = parse("{foo: true, bar: false}");
2599  @endcode
2600  Emitting `bool` variables still defaults to `0`/`1`, like the default behaviour in the STL. To explicitly request `true`/`false` use `c4::fmt::boolalpha()`:
2601  @code{c++}
2602  node << var; // "1" or "0"
2603  node << c4::fmt::boolalpha(var); // "true" or "false"
2604  @endcode
2605 * 2020/September
2606  * [***Breaking change***] [MR#85](https://github.com/biojppm/rapidyaml/pull/85) null values in YAML are now parsed to null strings instead of YAML null token "~":
2607  @code{c++}
2608  auto tree = parse("{foo: , bar: ''}");
2609  // previous:
2610  assert(tree["foo"].val() == "~");
2611  assert(tree["bar"].val() == "");
2612  // now:
2613  assert(tree["foo"].val() == nullptr); // notice that this is now null
2614  assert(tree["bar"].val() == "");
2615  @endcode
2616  * [MR#85](https://github.com/biojppm/rapidyaml/pull/85) Commas after tags are now allowed:
2617  @code{yaml}
2618  {foo: !!str, bar: ''} # now the comma does not cause an error
2619  @endcode
2620  * [MR#81](https://github.com/biojppm/rapidyaml/pull/81): Always compile with extra pedantic warnings.
2621 * 2020/May
2622  * [***Breaking change***] the error callback now receives a source location object:
2623  @code{c++}
2624  // previous
2625  using pfn_error = void (*)(const char* msg, size_t msg_len, void *user_data);
2626  // now:
2627  using pfn_error = void (*)(const char* msg, size_t msg_len, Location location, void *user_data);
2628  @endcode
2629  * Parser fixes to improve test suite success: [MR#73](https://github.com/biojppm/rapidyaml/pull/73), [MR#71](https://github.com/biojppm/rapidyaml/pull/71), [MR#68](https://github.com/biojppm/rapidyaml/pull/68), [MR#67](https://github.com/biojppm/rapidyaml/pull/67), [MR#66](https://github.com/biojppm/rapidyaml/pull/66)
2630  * Fix compilation as DLL on windows [MR#69](https://github.com/biojppm/rapidyaml/pull/69)