From d128813e6cc8b1ed7395d21d5a2c7dee1ff785ec Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Mon, 15 Apr 2024 03:31:54 +0100 Subject: [PATCH] Improve doxygen docs --- README.md | 6 +- doc/Doxyfile | 5 + doc/doxy_main.md | 20 +-- doc/index.rst | 82 ++++++++- doc/sphinx_api_documentation.rst | 52 ------ doc/sphinx_is_it_rapid.rst | 49 +++--- doc/sphinx_quicklinks.rst | 2 + ext/c4core | 2 +- samples/quickstart.cpp | 283 ++++++++++++++++++++++++------- src/c4/yml/common.hpp | 8 + 10 files changed, 347 insertions(+), 162 deletions(-) delete mode 100644 doc/sphinx_api_documentation.rst diff --git a/README.md b/README.md index 2b0ba02a..c763488c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Rapid YAML [![MIT Licensed](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/biojppm/rapidyaml/blob/master/LICENSE.txt) [![release](https://img.shields.io/github/v/release/biojppm/rapidyaml?color=g&include_prereleases&label=release%20&sort=semver)](https://github.com/biojppm/rapidyaml/releases) -[![Documentation Status](https://readthedocs.org/projects/rapidyaml/badge/?version=latest)](https://rapidyaml.readthedocs.io/en/latest/?badge=latest) +[![Documentation Status](https://readthedocs.org/projects/rapidyaml/badge/?version=latest)](https://rapidyaml.readthedocs.io/latest/?badge=latest) [![PyPI](https://img.shields.io/pypi/v/rapidyaml?color=g)](https://pypi.org/project/rapidyaml/) [![Gitter](https://badges.gitter.im/rapidyaml/community.svg)](https://gitter.im/rapidyaml/community) @@ -51,7 +51,7 @@ ryml is written in C++11, and compiles cleanly with: * Intel Compiler ryml's API documentation is [available at -ReadTheDocs](https://rapidyaml.readthedocs.io/en/latest/). +ReadTheDocs](https://rapidyaml.readthedocs.io/latest/). ryml is [extensively unit-tested in Linux, Windows and MacOS](https://github.com/biojppm/rapidyaml/actions). The tests cover @@ -239,7 +239,7 @@ level API for accessing and traversing the data tree. The following snippet is a very quick overview taken from quickstart sample ([see on -doxygen](https://rapidyaml.readthedocs.io/en/latest/group__doc__quickstart.html)/[see +doxygen](https://rapidyaml.readthedocs.io/latest/group__doc__quickstart.html)/[see on github](samples/quickstart.cpp). After cloning ryml (don't forget the `--recursive` flag for git), you can very easily build and run this executable using any of the build samples, eg the diff --git a/doc/Doxyfile b/doc/Doxyfile index 8cddb3f0..2348b229 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -957,6 +957,9 @@ INPUT = \ ../ext/c4core/src/c4/charconv.hpp \ ../ext/c4core/src/c4/format.hpp \ ../ext/c4core/src/c4/base64.hpp \ + ../ext/c4core/src/c4/std/string.hpp \ + ../ext/c4core/src/c4/std/string_view.hpp \ + ../ext/c4core/src/c4/std/vector.hpp \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -2495,6 +2498,8 @@ PREDEFINED = \ "C4_MUST_BE_TRIVIAL_COPY(cls)= " \ "C4_NO_INLINE= " \ "C4_NO_UBSAN_IOVRFLW= " \ + "C4_NODISCARD= " \ + "C4_NORETURN= " \ "C4_PURE= " \ "C4_REQUIRE_RW(ty)=ty " \ "C4_RESTRICT= " \ diff --git a/doc/doxy_main.md b/doc/doxy_main.md index 749ecf16..04afe2c0 100644 --- a/doc/doxy_main.md +++ b/doc/doxy_main.md @@ -10,25 +10,7 @@ * @ref doc_node_type * @ref doc_tree * @ref doc_node_classes - * For serialization/deserialization: - * See @ref sample_scalar_types for when the type is scalar (a leaf node in the YAML tree, containing a string representation): - * See examples on how to @ref sample_to_chars_scalar - * See examples on how to @ref sample_from_chars_scalar - * See the sample @ref sample::sample_user_scalar_types - * When serializing floating point values in C++ earlier than 17, - be aware that there may be a truncation of the precision with - the default to_chars implementation. To enforce a particular - precision, use for example @ref c4::fmt::real, or call - directly @ref c4::ftoa or @ref c4::dtoa, or any other method - (remember that ryml only stores the final string, so nothing - prevents you from creating it). See the relevant sample: @ref - sample::sample_float_precision. - * See @ref sample_container_types for when the type is a container (ie, a node which has children, which may themselves be containers). - * See the sample @ref sample::sample_user_container_types - * ryml does not use any STL containers internally, but it can be - used to serialize and deserialize these containers. See @ref - sample::sample_std_types for an example. See the header @ref - ryml_std.hpp and also the headers it includes. + * For serialization/deserialization, see @ref doc_serialization. * @ref doc_tag_utils - how to resolve tags * @ref doc_callbacks - how to set up error/allocation/deallocation callbacks either globally for the library, or for specific objects diff --git a/doc/index.rst b/doc/index.rst index 7bd30ed8..67a09597 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -12,17 +12,17 @@ and eat it too. Being rapid is definitely NOT the same as being unpractical, so ryml was written with easy AND efficient usage in mind. -ryml is available as a single header file, or it can be used as a -simple library with cmake -- both separately (ie -build -> install -> ``find_package()``) or together with your project (ie with +ryml is available both as a single header file, or as a simple library +with cmake -- both separately (ie build -> install -> +``find_package()``) or together with your project (ie with ``add_subdirectory()``). (See below for examples). ryml can use custom global and per-tree memory allocators and error handler callbacks, and is exception-agnostic. ryml provides a default implementation for the allocator (using ``std::malloc()``) and error -handlers (using either exceptions, ``longjmp()`` or ``std::abort()``), -but you can opt out of and provide your own memory allocation and -error callbacks. +handlers (using either exceptions or ``std::abort()``), but you can +opt out the default implementation and provide your own memory +allocation and error callbacks. For maximum portability, ryml does not depend on the STL, ie, it does not use any std container as part of its data structures. But ryml can @@ -53,10 +53,78 @@ Table of contents .. toctree:: :maxdepth: 3 - ./sphinx_api_documentation + Doxygen docs ./sphinx_quicklinks ./sphinx_is_it_rapid ./sphinx_yaml_standard ./sphinx_using ./sphinx_other_languages ./sphinx_alternative_libraries + + +API teaser +========== + +Here's a short teaser from the API quickstart overview (`see on +doxygen `_ / `see full code on +github +`_): + +.. code-block:: c++ + + // Parse YAML code in place, potentially mutating the buffer: + char yml_buf[] = "{foo: 1, bar: [2, 3], john: doe}"; + ryml::Tree tree = ryml::parse_in_place(yml_buf); + + // read from the tree: + ryml::NodeRef bar = tree["bar"]; + CHECK(bar[0].val() == "2"); + CHECK(bar[1].val() == "3"); + CHECK(bar[0].val().str == yml_buf + 15); // points at the source buffer + CHECK(bar[1].val().str == yml_buf + 18); + + // deserializing: + int bar0 = 0, bar1 = 0; + bar[0] >> bar0; + bar[1] >> bar1; + CHECK(bar0 == 2); + CHECK(bar1 == 3); + + // serializing: + bar[0] << 10; // creates a string in the tree's arena + bar[1] << 11; + CHECK(bar[0].val() == "10"); + CHECK(bar[1].val() == "11"); + + // add nodes + bar.append_child() << 12; // see also operator= (explanation below) + CHECK(bar[2].val() == "12"); + + // emit tree + // to std::string + CHECK(ryml::emitrs_yaml(tree) == R"(foo: 1 +bar: + - 10 + - 11 + - 12 +john: doe +)"); + std::cout << tree; // emit to stdout + ryml::emit_yaml(tree, stdout); // emit to file + + // emit node + ryml::ConstNodeRef foo = tree["foo"]; + // to std::string + CHECK(ryml::emitrs_yaml(foo) == "foo: 1\n"); + std::cout << foo; // emit node to stdout + ryml::emit_yaml(foo, stdout); // emit node to file + + +.. note:: + Please refer to the `Doxygen documentation + <./doxygen/index.html>`_, and read the `overview sample + `_; + this will quickly teach you the basic concepts and caveats, which + will save you a lot of time. + +.. include:: sphinx_try_quickstart.rst diff --git a/doc/sphinx_api_documentation.rst b/doc/sphinx_api_documentation.rst deleted file mode 100644 index 383d314b..00000000 --- a/doc/sphinx_api_documentation.rst +++ /dev/null @@ -1,52 +0,0 @@ -API documentation -================= - -.. note:: - Please refer to the `Doxygen documentation - <./doxygen/index.html>`_, and please read the `overview sample - `_; - it will quickly teach you the basic concepts and caveats, which - will save you a lot of time. - - -.. include:: sphinx_try_quickstart.rst - -Here's a short selection from the quickstart overview (`see on -doxygen `_ / `see full code -on github `_): - -.. code-block:: c++ - - // Parse YAML code in place, potentially mutating the buffer: - char yml_buf[] = "{foo: 1, bar: [2, 3], john: doe}"; - ryml::Tree tree = ryml::parse_in_place(yml_buf); - - // read from the tree: - ryml::NodeRef bar = tree["bar"]; - CHECK(bar[0].val() == "2"); - CHECK(bar[1].val() == "3"); - CHECK(bar[0].val().str == yml_buf + 15); // points at the source buffer - CHECK(bar[1].val().str == yml_buf + 17); - - // deserializing: - int bar0 = 0, bar1 = 0; - bar[0] >> bar0; - bar[1] >> bar1; - CHECK(bar0 == 2); - CHECK(bar1 == 3); - - // serializing: - bar[0] << 10; // creates a string in the tree's arena - bar[1] << 11; - CHECK(bar[0].val() == "10"); - CHECK(bar[1].val() == "11"); - - // add nodes - bar.append_child() << 12; - CHECK(bar[1].val() == "12"); - - // emit to stdout - std::cout << tree; - - // emit to std::string - CHECK(emitrs_yaml(tree) == "{foo: 1,bar: [10,11,12],john: doe}"); diff --git a/doc/sphinx_is_it_rapid.rst b/doc/sphinx_is_it_rapid.rst index df31e667..6f34bfd8 100644 --- a/doc/sphinx_is_it_rapid.rst +++ b/doc/sphinx_is_it_rapid.rst @@ -38,9 +38,10 @@ against other libraries. Comparison with yaml-cpp ------------------------ -The first result set is for Windows, and is using a `appveyor.yml config -file `__. A comparison of these results is -summarized on the table below: +The first result set is for Windows, and is using a `appveyor.yml +config file +`__. A +comparison of these results is summarized on the table below: =========================== ===== ======= ========== Read rates (MB/s) ryml yamlcpp compared @@ -49,12 +50,13 @@ appveyor / vs2017 / Release 101.5 5.3 20x / 5.2% appveyor / vs2017 / Debug 6.4 0.0844 76x / 1.3% =========================== ===== ======= ========== -The next set of results is taken in Linux, comparing g++ 8.2 and clang++ -7.0.1 in parsing a YAML buffer from a `travis.yml config -file `__ or a JSON buffer from a -`compile_commands.json file `__. You -can `see the full results -here `__. Summarizing: +The next set of results is taken in Linux, comparing g++ 8.2 and +clang++ 7.0.1 in parsing a YAML buffer from a `travis.yml config file +`__ +or a JSON buffer from a `compile_commands.json file +`__. You +can `see the full results here +`__. Summarizing: ========================== ===== ======= ======== Read rates (MB/s) ryml yamlcpp compared @@ -86,13 +88,14 @@ Performance reading JSON So how does ryml compare against other JSON readers? Well, it may not be the fastest, but it's definitely ahead of the pack! -The benchmark is the `same as above `__, and it is -reading the -`compile_commands.json `__, The -``_arena`` suffix notes parsing a read-only buffer (so buffer copies are -performed), while the ``_inplace`` suffix means that the source buffer -can be parsed in place. The ``_reuse`` means the data tree and/or parser -are reused on each benchmark repeat. +The benchmark is the `same as above +`__, +and it is reading the `compile_commands.json +`__, +The ``_arena`` suffix notes parsing a read-only buffer (so buffer +copies are performed), while the ``_inplace`` suffix means that the +source buffer can be parsed in place. The ``_reuse`` means the data +tree and/or parser are reused on each benchmark repeat. Here’s what we get with g++ 8.2: @@ -127,12 +130,14 @@ result). Performance emitting -------------------- -`Emitting benchmarks `__ also show similar speedups from -the existing libraries, also anecdotally reported by some users `(eg, -here’s a user reporting 25x speedup from -yaml-cpp) `__. -Also, in some cases (eg, block folded multiline scalars), the speedup is -as high as 200x (eg, 7.3MB/s -> 1.416MG/s). +`Emitting benchmarks +`__ +also show similar speedups from the existing libraries, also +anecdotally reported by some users `(eg, here’s a user reporting 25x +speedup from yaml-cpp) +`__. +Also, in some cases (eg, block folded multiline scalars), the speedup +is as high as 200x (eg, 7.3MB/s -> 1.416MG/s). Serialization performance diff --git a/doc/sphinx_quicklinks.rst b/doc/sphinx_quicklinks.rst index 2c4e3193..e32e211b 100644 --- a/doc/sphinx_quicklinks.rst +++ b/doc/sphinx_quicklinks.rst @@ -9,6 +9,8 @@ Quick links * `Pull Requests `_ + * `Kanban board `_ + * Latest release: `0.5.0 `_ * `Release page [0.5.0] `_ diff --git a/ext/c4core b/ext/c4core index 98f783e4..1cd92b7f 160000 --- a/ext/c4core +++ b/ext/c4core @@ -1 +1 @@ -Subproject commit 98f783e462daddfe8b12ea2741515315fb1c44af +Subproject commit 1cd92b7f3372e020eca5a1bbb57f5e7059eb8cdd diff --git a/samples/quickstart.cpp b/samples/quickstart.cpp index 6792e418..f20e7077 100644 --- a/samples/quickstart.cpp +++ b/samples/quickstart.cpp @@ -34,7 +34,8 @@ // (Each function addresses a topic and is fully self-contained. Jump // to the function to find out about its topic.) namespace sample { -void sample_quick_overview(); ///< brief overview of most common features +void sample_lightning_overview(); ///< lightning overview of most common features +void sample_quick_overview(); ///< quick overview of most common features void sample_substr(); ///< about ryml's string views (from c4core) void sample_parse_file(); ///< ready-to-go example of parsing a file from disk void sample_parse_in_place(); ///< parse a mutable YAML source buffer @@ -72,6 +73,7 @@ int report_checks(); int main() { + sample::sample_lightning_overview(); sample::sample_quick_overview(); sample::sample_substr(); sample::sample_parse_file(); @@ -247,7 +249,64 @@ struct ScopedErrorHandlerExample : public ErrorHandlerExample ~ScopedErrorHandlerExample() { ryml::set_callbacks(defaults); check_effect(false); } }; -/** @} */ // sample_helpers +/** @} */ // doc_sample_helpers + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +/** a lightning tour over most features + * see @ref sample_quick_overview */ +void sample_lightning_overview() +{ + // Parse YAML code in place, potentially mutating the buffer: + char yml_buf[] = "{foo: 1, bar: [2, 3], john: doe}"; + ryml::Tree tree = ryml::parse_in_place(yml_buf); + + // read from the tree: + ryml::NodeRef bar = tree["bar"]; + CHECK(bar[0].val() == "2"); + CHECK(bar[1].val() == "3"); + CHECK(bar[0].val().str == yml_buf + 15); // points at the source buffer + CHECK(bar[1].val().str == yml_buf + 18); + + // deserializing: + int bar0 = 0, bar1 = 0; + bar[0] >> bar0; + bar[1] >> bar1; + CHECK(bar0 == 2); + CHECK(bar1 == 3); + + // serializing: + bar[0] << 10; // creates a string in the tree's arena + bar[1] << 11; + CHECK(bar[0].val() == "10"); + CHECK(bar[1].val() == "11"); + + // add nodes + bar.append_child() << 12; // see also operator= (explanation below) + CHECK(bar[2].val() == "12"); + + // emit tree + // to std::string + CHECK(ryml::emitrs_yaml(tree) == R"(foo: 1 +bar: + - 10 + - 11 + - 12 +john: doe +)"); + std::cout << tree; // emit to stdout + ryml::emit_yaml(tree, stdout); // emit to file + + // emit node + ryml::ConstNodeRef foo = tree["foo"]; + // to std::string + CHECK(ryml::emitrs_yaml(foo) == "foo: 1\n"); + std::cout << foo; // emit node to stdout + ryml::emit_yaml(foo, stdout); // emit node to file +} //----------------------------------------------------------------------------- @@ -274,6 +333,8 @@ void sample_quick_overview() // // - reuse an existing parser (advised) // + // - parse into an existing node deep in a tree + // // Note: it will always be significantly faster to parse in place // and reuse tree+parser. // @@ -2373,7 +2434,8 @@ void sample_tree_arena() those types that should be serialized as strings in leaf nodes), you just need to define the appropriate overloads of to_chars and from_chars for those types; see @ref sample_user_scalar_types for - an example on how to achieve this. */ + an example on how to achieve this, and see @ref doc_serialization + for more information on serialization. */ void sample_fundamental_types() { ryml::Tree tree; @@ -2437,7 +2499,8 @@ void sample_fundamental_types() //----------------------------------------------------------------------------- -/** Shows how to deal with empty/null values. See also @ref c4::yml::Tree::val_is_null */ +/** Shows how to deal with empty/null values. See also @ref + * c4::yml::Tree::val_is_null */ void sample_empty_null_values() { // reading empty/null values - see also sample_formatting() @@ -2600,8 +2663,10 @@ str_tilde: ~ //----------------------------------------------------------------------------- -/** ryml provides facilities for formatting (imported from c4core into - * the ryml namespace) - see @ref doc_format_utils +/** ryml provides facilities for formatting/deformatting (imported + * from c4core into the ryml namespace). See @ref doc_format_utils + * . These functions are very useful to serialize and deserialize + * scalar types; see @ref doc_serialization . */ void sample_formatting() { @@ -3233,13 +3298,94 @@ QmVsaWtlIGZvciB3YW50IG9mIHJhaW4sIHdoaWNoIEkgY291bGQgd2VsbCBiZXRlZW0gdGhlbSBmcm9t } +//----------------------------------------------------------------------------- +// Serialization info + +} // namespace sample // because we want the doxygen document above to show up in the proper place +/** @addtogroup doc_serialization + * + * ## Fundamental types + * + * ryml provides serialization/deserialization utilities for all + * fundamental data types in @ref doc_charconv . + * + * - See @ref sample::sample_fundamental_types() for basic examples + * of serialization of fundamental types. + * - See @ref sample::sample_empty_null_values() for different ways + * to serialize and deserialize empty and null values/ + * - When serializing floating point values in C++ earlier than + * 17, be aware that there may be a truncation of the precision + * with the default float/double implementations of @ref + * doc_to_chars. To enforce a particular precision, use for + * example @ref c4::fmt::real, or call directly @ref c4::ftoa() or + * @ref c4::dtoa(), or any other method (remember that ryml only + * stores the final string in the tree, so nothing prevents you from + * creating it in whatever way is most suitable). See the relevant + * sample: @ref sample::sample_float_precision(). + * - You can also serialize and deserialize base64: see @ref + * doc_base64 and @ref sample::sample_base64 + * + * To serialize/deserialize any non-fundamental type will require + * that you instruct ryml on how to achieve this. That will differ + * based on whether the type is scalar or container. + * + * + * ## User scalar types + * + * See @ref doc_sample_scalar_types for serializing user scalar types + * (ie leaf nodes in the YAML tree, containing a string + * representation): + * + * - See examples on how to @ref doc_sample_to_chars_scalar + * - See examples on how to @ref doc_sample_from_chars_scalar + * - See the sample @ref sample::sample_user_scalar_types + * - See the sample @ref sample::sample_formatting for examples + * of functions from @ref doc_format_utils that will be very + * helpful in implementing custom `to_chars()`/`from_chars()` + * functions. + * - See @ref doc_charconv for the implementations of + * `to_chars()`/`from_chars()` for the fundamental types. + * - See @ref doc_substr and @ref sample::sample_substr() for the + * many useful utilities in the substring class. + * + * + * ## User container types + * + * - See @ref doc_sample_container_types for when the type is a + * container (ie, a node which has children, which may themselves be + * containers). + * + * - See the sample @ref sample::sample_user_container_types + * + * - See the sample @ref sample::sample_std_types, and also... + * + * + * ## STL types + * + * ryml does not use any STL containers internally, but it can be + * used to serialize and deserialize these containers. See @ref + * sample::sample_std_types() for an example. See the header @ref + * ryml_std.hpp and also the headers it includes: + * + * - scalar types: + * - for `std::string`: @ref ext/c4core/src/c4/std/string.hpp + * - for `std::string_view`: @ref ext/c4core/src/c4/std/string_view.hpp + * - for `std::vector`: @ref ext/c4core/src/c4/std/vector.hpp + * - container types: + * - for `std::vector`: @ref src/c4/yml/std/vector.hpp + * - for `std::map`: @ref src/c4/yml/std/map.hpp + * + */ +namespace sample { // because we want the doxygen document above to show up in the proper place + + //----------------------------------------------------------------------------- // user scalar types: implemented in ryml through to_chars() + from_chars() /** @addtogroup doc_sample_helpers * @{ */ -/** @defgroup sample_scalar_types Serialize/deserialize scalar types +/** @defgroup doc_sample_scalar_types Serialize/deserialize scalar types * @{ */ template struct vec2 { T x, y; }; ///< example scalar type, serialized and deserialized @@ -3254,10 +3400,10 @@ template struct emit_only_vec2 { T x, y; }; ///< example scalar type, s template struct emit_only_vec3 { T x, y, z; }; ///< example scalar type, serialized only template struct emit_only_vec4 { T x, y, z, w; }; ///< example scalar type, serialized only -/** @defgroup sample_to_chars_scalar Define to_chars to write scalar types +/** @defgroup doc_sample_to_chars_scalar Define to_chars to write scalar types * * @brief To serialize user scalar types, implement the appropriate - * function to_chars (see also @ref doc_to_chars) + * function to_chars (see also @ref doc_to_chars): * * ```cpp * // any of these can be used: @@ -3265,6 +3411,8 @@ template struct emit_only_vec4 { T x, y, z, w; }; ///< example scalar t * size_t to_chars(substr buf, T v); // this also works, and is good when the type is small * ``` * + * See the sample @ref sample_user_scalar_types() for an example usage. + * * Your implementation of to_chars must format v to the given string * view + return the number of characters written into it. The view * size (buf.len) must be strictly respected. Return the number of @@ -3277,21 +3425,28 @@ template struct emit_only_vec4 { T x, y, z, w; }; ///< example scalar t * formatting facilities in @ref doc_format_utils and @ref doc_charconv; * refer to their documentation for further details. But this is not * mandatory, and anything can be used, provided that the implemented - * to_chars fulfills its contract, described above. - * - * To harness [C++'s ADL rules](http://en.cppreference.com/w/cpp/language/adl), - * it is important to overload these functions in the namespace of the type - * you're serializing (or in the c4::yml namespace). + * `to_chars()` fulfills its contract, described above. * - * Please take note of the following pitfall when using serialization - * functions: you have to include the header with the serialization - * before any other headers that use functions from it. see the - * include order at the top of this file. + * @warning Because of [C++'s ADL + * rules](http://en.cppreference.com/w/cpp/language/adl), **it is + * required to overload these functions in the namespace of the type** + * you're serializing (or in the c4 namespace, or in the c4::yml + * namespace). [Here's an example of an issue where failing to do this + * was causing problems in some + * platforms](https://github.com/biojppm/rapidyaml/issues/424) * - * This constraint also applies to the conversion functions for your - * types; just like with the STL's headers, they should be included - * prior to ryml's headers. + * @note Please take note of the following pitfall when using + * serialization functions: you may have to include the header with + * your `to_chars()` implementation before any other headers that use + * functions from it. See the include order at the top of this source + * file. This constraint also applies to the conversion functions for + * your types; just like with the STL's headers, they should be + * included prior to ryml's headers. Lately, some effort was directed + * to provide forward declarations to alleviate this problem, but it + * may still occur. * + * @see string.hpp + * @see string_view.hpp * @{ */ template size_t to_chars(ryml::substr buf, vec2 v) { return ryml::format(buf, "({},{})", v.x, v.y); } @@ -3304,7 +3459,7 @@ template size_t to_chars(ryml::substr buf, emit_only_vec4 v) { retur /** @} */ -/** @defgroup sample_from_chars_scalar Define from_chars to read scalar types +/** @defgroup doc_sample_from_chars_scalar Define from_chars to read scalar types * * @brief To deserialize user scalar types, implement the * function `bool from_chars(csubstr buf, T *val)`; see @ref @@ -3322,18 +3477,23 @@ template size_t to_chars(ryml::substr buf, emit_only_vec4 v) { retur * mandatory, and anything can be used, provided that the implemented * from_chars fulfills its contract, described above. * - * To harness [C++'s ADL rules](http://en.cppreference.com/w/cpp/language/adl), - * it is important to overload these functions in the namespace of the type - * you're serializing (or in the c4::yml namespace). + * @warning Because of [C++'s ADL + * rules](http://en.cppreference.com/w/cpp/language/adl), **it is + * required to overload these functions in the namespace of the type** + * you're serializing (or in the c4 namespace, or in the c4::yml + * namespace). [Here's an example of an issue where failing to do this + * was causing problems in some + * platforms](https://github.com/biojppm/rapidyaml/issues/424) * - * Please take note of the following pitfall when using serialization - * functions: you have to include the header with the serialization - * before any other headers that use functions from it. see the - * include order at the top of this file. - * - * This constraint also applies to the conversion functions for your - * types; just like with the STL's headers, they should be included - * prior to ryml's headers. + * @note Please take note of the following pitfall when using + * serialization functions: you may have to include the header with + * your `from_chars()` implementation before any other headers that use + * functions from it. See the include order at the top of this source + * file. This constraint also applies to the conversion functions for + * your types; just like with the STL's headers, they should be + * included prior to ryml's headers. Lately, some effort was directed + * to provide forward declarations to alleviate this problem, but it + * may still occur. * * @{ */ @@ -3344,15 +3504,15 @@ template bool from_chars(ryml::csubstr buf, vec4 *v) { size_t ret = template bool from_chars(ryml::csubstr buf, parse_only_vec2 *v) { size_t ret = ryml::unformat(buf, "({},{})", v->x, v->y); return ret != ryml::yml::npos; } template bool from_chars(ryml::csubstr buf, parse_only_vec3 *v) { size_t ret = ryml::unformat(buf, "({},{},{})", v->x, v->y, v->z); return ret != ryml::yml::npos; } template bool from_chars(ryml::csubstr buf, parse_only_vec4 *v) { size_t ret = ryml::unformat(buf, "({},{},{},{})", v->x, v->y, v->z, v->w); return ret != ryml::yml::npos; } -/** @} */ // sample_from_chars_scalar +/** @} */ // doc_sample_from_chars_scalar -/** @} */ // sample_scalar_types -/** @} */ // sample_helpers +/** @} */ // doc_sample_scalar_types +/** @} */ // doc_sample_helpers /** to add scalar types (ie leaf types converting to/from string), * define the functions above for those types. See @ref - * sample_scalar_types. */ + * doc_sample_scalar_types. */ void sample_user_scalar_types() { ryml::Tree t; @@ -3422,7 +3582,7 @@ v4: '(40,41,42,43)' /** @addtogroup doc_sample_helpers * @{ */ -/** @defgroup sample_container_types Serialize/deserialize container types +/** @defgroup doc_sample_container_types Serialize/deserialize container types * * To serialize/deserialize container types to a tree, implement the * appropriate functions: @@ -3432,14 +3592,26 @@ v4: '(40,41,42,43)' * bool read(ryml::ConstNodeRef const& n, T *seq); * ``` * - * Please take note of the following pitfall when using serialization - * functions: you have to include the header with the serialization - * before any other headers that use functions from it. see the - * include order at the top of this file. + * @warning Because of [C++'s ADL + * rules](http://en.cppreference.com/w/cpp/language/adl), **it is + * required to overload these functions in the namespace of the type** + * you're serializing (or in the c4 namespace, or in the c4::yml + * namespace). [Here's an example of an issue where failing to do this + * was causing problems in some + * platforms](https://github.com/biojppm/rapidyaml/issues/424) + * + * @note Please take note of the following pitfall when using + * serialization functions: you may have to include the header with + * your `write()` or `read()` implementation before any other headers + * that use functions from it. See the include order at the top of + * this source file. This constraint also applies to the conversion + * functions for your types; just like with the STL's headers, they + * should be included prior to ryml's headers. Lately, some effort was + * directed to provide forward declarations to alleviate this problem, + * but it may still occur. * - * This constraint also applies to the conversion functions for your - * types; just like with the STL's headers, they should be included - * prior to ryml's headers. + * @see sample::sample_container_types + * @see sample::sample_std_types * * @{ */ @@ -3528,13 +3700,15 @@ bool read(ryml::ConstNodeRef const& n, my_type *val) return true; } -/** @} */ // sample_container_types +/** @} */ // doc_sample_container_types /** @} */ // sample_helpers /** shows how to serialize/deserialize container types. - * @see sample_container_types */ + * @see doc_sample_container_types + * @see sample_std_types + * */ void sample_user_container_types() { my_type mt_in{ @@ -3591,17 +3765,11 @@ v4: '(40,41,42,43)' //----------------------------------------------------------------------------- -// -// Please take note of the following pitfall when using serialization -// functions: you have to include the header with the serialization -// before any other headers that use functions from it. see the -// include order at the top of this file. -// -// This constraint also applies to the conversion functions for your -// types; just like with the STL's headers, they should be included -// prior to ryml's headers. -/** demonstrates usage with the std implementations provided by ryml in the ryml_std.hpp header */ +/** demonstrates usage with the std implementations provided by ryml + in the ryml_std.hpp header + @see @ref doc_sample_container_types + @see also the STL section in @ref doc_serialization */ void sample_std_types() { std::string yml_std_string = R"(- v2: '(20,21)' @@ -4950,7 +5118,6 @@ C4_NORETURN void ErrorHandlerExample::s_error(const char* msg, size_t len, ryml: /** this is the where the callback implementation goes. Remember that it must not return. */ C4_NORETURN void ErrorHandlerExample::on_error(const char* msg, size_t len, ryml::Location loc) { - std::cout << "aqui foo!\n"; std::string full_msg = ryml::formatrs( "{}:{}:{} ({}B): ERROR: {}", loc.name, loc.line, loc.col, loc.offset, ryml::csubstr(msg, len)); diff --git a/src/c4/yml/common.hpp b/src/c4/yml/common.hpp index d7f9edba..d08281ea 100644 --- a/src/c4/yml/common.hpp +++ b/src/c4/yml/common.hpp @@ -75,6 +75,14 @@ * @see sample::sample_per_tree_allocator */ +/** @defgroup doc_serialization Serialization/deserialization + * + * Contains information on how to serialize and deserialize + * fundamental types, user scalar types, user container types and + * interop with std scalar/container types. + * + */ + /** @defgroup doc_tag_utils Tag utilities * @see sample::sample_tags */