diff --git a/README.md b/README.md index c1d50ec..d2908f7 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ int main() - [Visiting a toml::value](#visiting-a-tomlvalue) - [Constructing a toml::value](#constructing-a-tomlvalue) - [Preserving Comments](#preserving-comments) -- [Customizing container](#customizing-container) +- [Customizing containers](#customizing-containers) - [TOML literal](#toml-literal) - [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types) - [Invalid UTF-8 Codepoints](#invalid-utf-8-codepoints) @@ -305,6 +305,8 @@ The above code works with the following toml file. ```toml "physical.color" = "orange" +# equivalent to {"physical.color": "orange"}, +# NOT {"physical": {"color": "orange"}}. ``` ## Casting a toml value @@ -323,9 +325,9 @@ contain one of the following types. - `toml::local_datetime` - `toml::offset_datetime` - `toml::array` (by default, `std::vector`) - - It depends. See [customize toml::value](#customize-toml-value) for detail. + - It depends. See [customizing containers](#customizing-containers) for detail. - `toml::table` (by default, `std::unordered_map`) - - It depends. See [customize toml::value](#customize-toml-value) for detail. + - It depends. See [customizing containers](#customizing-containers) for detail. To get a value inside, you can use `toml::get()`. The usage is the same as `toml::find` (actually, `toml::find` internally uses `toml::get`). @@ -526,7 +528,7 @@ const auto first = toml::get>(a_of_a.at(0)); ``` You can change the implementation of `toml::array` with `std::deque` or some -other array-like container. See [Customizing container](#customizing-container) +other array-like container. See [Customizing containers](#customizing-containers) for detail. ### Converting a table @@ -561,7 +563,7 @@ if(data.count("title") != 0) ``` You can change the implementation of `toml::table` with `std::map` or some -other map-like container. See [Customizing container](#customizing-container) +other map-like container. See [Customizing containers](#customizing-containers) for detail. ### Getting an array of tables @@ -728,13 +730,105 @@ each other. TODO -## Preserving Comments +## Preserving comments -TODO +After toml11 v3, you can choose whether comments are preserved or not. -## Customizing container +```cpp +const auto data1 = toml::parse("example.toml"); +const auto data2 = toml::parse("example.toml"); +``` -TODO +Comments related to a value can be obtained by `toml::value::comments()`. +The return value has the same interface as `std::vector`. + +```cpp +const auto& com = v.comments(); +for(const auto& c : com) +{ + std::cout << c << std::endl; +} +``` + +Comments just before and just after (within the same line) a value are kept in a value. + +```toml +# this is a comment for v1. +v1 = "foo" + +v2 = "bar" # this is a comment for v2. +# Note that this comment is NOT a comment for v2. + +# this comment is not related to any value +# because there are empty lines between v3. +# this comment will be ignored even if you set `preserve_comments`. + +# this is a comment for v3 +# this is also a comment for v3. +v3 = "baz" # ditto. +``` + +Each comment line becomes one element of a `std::vector`. + +Hash signs will be removed, but spaces after hash sign will not be removed. + +```cpp +v1.comments().at(0) == " this is a comment for v1."s; + +v2.comments().at(1) == " this is a comment for v1."s; + +v3.comments().at(0) == " this is a comment for v3."s; +v3.comments().at(1) == " this is also a comment for v3."s; +v3.comments().at(2) == " ditto."s; +``` + +Note that a comment just after an opening brace of an array will not be a +comment for the array. + +```toml +# this is a comment for a. +a = [ # this is not a comment for a. this will be ignored. + 1, 2, 3, + # this is a comment for `42`. + 42, # this is also a comment for `42`. + 5 +] # this is a comment for a. +``` + +You can also append comments. The interfaces are the same as `std::vector`. + +```cpp +v.comments().push_back(" add new comment."); +``` + +When `toml::discard_comments` is chosen, `value::comments()` will always be kept +empty. All the modification on comments would be ignored. + +The comments will also be serialized. If comments exist, those comments will be +added just before the values. + +## Customizing containers + +Actually, `toml::basic_value` has 3 template arguments. + +```cpp +template class Table = std::unordered_map, + template class Array = std::vector> +class basic_value; +``` + +This enables you to change the containers used inside. E.g. you can use +`std::map` to contain a table object instead of `std::unordered_map`. +And also can use `std::deque` as a array object instead of `std::vector`. + +You can set these parameters while calling `toml::parse` function. + +```cpp +const auto data = toml::parse< + toml::preserve_comments, std::map, std::deque + >("example.toml"); +``` ## TOML literal @@ -798,6 +892,10 @@ add a comma after the first element (like `[1,]`). "[[1],]"_toml; // ditto. ``` +NOTE: `_toml` literal returns a `toml::value` that does not have comments. + + + ## Conversion between toml value and arbitrary types You can also use `toml::get` and other related functions with the types you defined @@ -995,33 +1093,27 @@ you will get an error message like this. ### Obtaining location information -You can get `source_location` by calling `toml::value::location()`. +You can also format error messages in your own way by using `source_location`. ```cpp -const toml::value v = /**/; -const toml::source_location sl = v.location(); -``` - -You can use it to format your own error message. - -```cpp -class source_location { - public: - -// +-- line() +-- region of interest (region() == 9) -// v .---+---. -// 12 | value = "foo bar" -// ^ -// +-- column() - +struct source_location +{ std::uint_least32_t line() const noexcept; std::uint_least32_t column() const noexcept; std::uint_least32_t region() const noexcept; - std::string const& file_name() const noexcept; - std::string const& line_str() const noexcept; // the line itself -// ... + std::string const& line_str() const noexcept; }; +// +-- line() +--- length of the region (here, region() == 9) +// v .---+---. +// 12 | value = "foo bar" <- line_str() returns the line itself. +// ^-------- column() points here +``` + +You can get this by +```cpp +const toml::value v = /*...*/; +const toml::source_location loc = v.location(); ``` ## Serializing TOML data @@ -1121,6 +1213,7 @@ const auto serial = toml::format(data, /*width = */ 0, /*prec = */ 17); ``` When you pass a comment-preserving-value, the comment will also be serialized. +An array or a table containing a value that has a comment would not be inlined. ## Underlying types @@ -1152,7 +1245,7 @@ that points to internal `std::string` by using `toml::get()` for co Because `std::chrono::system_clock::time_point` is a __time point__, not capable of representing a Local Time independent from a specific day. -It is recommended to get `Datetime`s as `std::chrono` classes through `toml::get`. +It is recommended to get `datetime`s as `std::chrono` classes through `toml::get`. ## Breaking Changes from v2 @@ -1163,14 +1256,20 @@ Between v2 and v3, those interfaces are rearranged. - `toml::parse` now returns a `toml::value`, not `toml::table`. - `toml::value` is now an alias of `toml::basic_value`. - See [Customizing containers](#customizing-containers) for detail. + - See [Customizing containers](#customizing-containers) for detail. - The elements of `toml::value_t` are renamed as `snake_case`. + - See [Underlying types](#underlying-types) for detail. - Supports for the CamelCaseNames are dropped. + - See [Underlying types](#underlying-types) for detail. - `(is|as)_float` has been removed to make the function names consistent with others. Since `float` is a keyword, toml11 named a float type as `toml::floating`. Also a `value_t` corresponds to `toml::floating` is named `value_t::floating`. So `(is|as)_floating` is introduced and `is_float` has been removed. + - See [Casting a toml::value](#casting-a-tomlvalue) and [Checking value type](#checking-value-type) for detail. +- `toml::find` for `toml::table` has been dropped. Use `toml::value` version instead. + - See [Finding a toml::value](#finding-a-tomlvalue) for detail. - Interface around comments. + - See [Preserving Comments](#preserving-comments) for detail. - An old `from_toml` has been removed Such a big change will not happen in the coming years. diff --git a/toml/get.hpp b/toml/get.hpp index 1859bbb..bc9f43f 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -423,48 +423,6 @@ T get(const basic_value& v) // ============================================================================ // find and get -// for toml::table. -template -detail::enable_if_t, - detail::is_basic_value>::value, - decltype(::toml::get(std::declval()))> -find(Table& tab, const toml::key& ky, std::string tn = "unknown table") -{ - if(tab.count(ky) == 0) - { - throw std::out_of_range(concat_to_string( - "[error] key \"", ky, "\" not found in ", tn)); - } - return ::toml::get(tab.at(ky)); -} -template -detail::enable_if_t, - detail::is_basic_value>::value, - decltype(::toml::get(std::declval()))> -find(Table const& tab, const toml::key& ky, std::string tn = "unknown table") -{ - if(tab.count(ky) == 0) - { - throw std::out_of_range(concat_to_string( - "[error] key \"", ky, "\" not found in ", tn)); - } - return ::toml::get(tab.at(ky)); -} -template -detail::enable_if_t, - detail::is_basic_value>::value, - decltype(::toml::get(std::declval()))> -find(typename std::remove_reference&& tab, const toml::key& ky, - std::string tn = "unknown table") -{ - if(tab.count(ky) == 0) - { - throw std::out_of_range(concat_to_string( - "[error] key \"", ky, "\" not found in ", tn)); - } - return ::toml::get(std::move(tab.at(ky))); -} - // ---------------------------------------------------------------------------- // these overloads do not require to set T. and returns value itself. template& v, const toml::key& ky, T&& opt) return get_or(tab.at(ky), std::forward(opt)); } -// =========================================================================== -// find_or(table, key, opt) - -// --------------------------------------------------------------------------- -// exact types (return type can be a reference) -template -detail::enable_if_t, detail::is_basic_value, - detail::is_exact_toml_type - >::value, T> const& -find_or(const Table& tab, const key& ky, const T& opt) -{ - if(tab.count(ky) == 0) {return opt;} - return get_or(tab.at(ky), opt); -} - -template -detail::enable_if_t, detail::is_basic_value, - detail::is_exact_toml_type - >::value, T>& -find_or(Table& tab, const key& ky, T& opt) -{ - if(tab.count(ky) == 0) {return opt;} - return get_or(tab[ky], opt); -} - -template -detail::enable_if_t, detail::is_basic_value, - detail::is_exact_toml_type - >::value, T>&& -find_or(typename std::remove_reference
::type&& tab, const key& ky, T&& opt) -{ - if(tab.count(ky) == 0) {return opt;} - return get_or(std::move(tab[ky]), std::forward(opt)); -} - -// --------------------------------------------------------------------------- -// std::string (return type can be a reference) -template -detail::enable_if_t, detail::is_basic_value, - std::is_same - >::value, std::string> const& -find_or(const Table& tab, const key& ky, const T& opt) -{ - if(tab.count(ky) == 0) {return opt;} - return get_or(tab.at(ky), opt); -} -template -detail::enable_if_t, detail::is_basic_value, - std::is_same - >::value, std::string>& -find_or(Table& tab, const key& ky, T& opt) -{ - if(tab.count(ky) == 0) {return opt;} - return get_or(tab[ky], opt); -} -template -detail::enable_if_t, detail::is_basic_value, - std::is_same - >::value, std::string> -find_or(Table&& tab, const key& ky, T&& opt) -{ - if(tab.count(ky) == 0) {return std::forward(opt);} - return get_or(std::move(tab[ky]), std::forward(opt)); -} - -// --------------------------------------------------------------------------- -// string literal (deduced as std::string) -template -detail::enable_if_t, - detail::is_basic_value, - detail::is_string_literal::type> - >::value, std::string> -find_or(const Table& tab, const key& ky, T&& opt) -{ - if(tab.count(ky) == 0) {return std::string(opt);} - return get_or(tab.at(ky), std::forward(opt)); -} - -// --------------------------------------------------------------------------- -// others (require type conversion and return type cannot be lvalue reference) -template -detail::enable_if_t, - detail::is_basic_value, - detail::negation>, - detail::negation>, - detail::negation::type>> - >::value, T> -find_or(const Table& tab, const key& ky, T&& opt) -{ - if(tab.count(ky) == 0) {return opt;} - return get_or(tab.at(ky), std::forward(opt)); -} - // ============================================================================ // expect