Merge branch remote into v3

This commit is contained in:
ToruNiina 2019-06-17 12:10:40 +09:00
commit 94bcf0aae9
2 changed files with 130 additions and 174 deletions

161
README.md
View File

@ -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<toml::value>`)
- 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<toml::key, toml::value>`)
- 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<T>()`. The usage is the same as
`toml::find<T>` (actually, `toml::find` internally uses `toml::get`).
@ -526,7 +528,7 @@ const auto first = toml::get<std::vector<int>>(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<toml::discard_comments >("example.toml");
const auto data2 = toml::parse<toml::preserve_comments>("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<std::string>`.
```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<std::string>`.
```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<typename Comment, // discard/preserve_comment
template<typename ...> class Table = std::unordered_map,
template<typename ...> 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<std::string>()` 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<discard_comment, std::vector, std::unordered_map>`.
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.

View File

@ -423,48 +423,6 @@ T get(const basic_value<C, M, V>& v)
// ============================================================================
// find and get
// for toml::table.
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<detail::is_map<Table>,
detail::is_basic_value<typename Table::mapped_type>>::value,
decltype(::toml::get<T>(std::declval<typename Table::mapped_type&>()))>
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<T>(tab.at(ky));
}
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<detail::is_map<Table>,
detail::is_basic_value<typename Table::mapped_type>>::value,
decltype(::toml::get<T>(std::declval<typename Table::mapped_type const&>()))>
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<T>(tab.at(ky));
}
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<detail::is_map<Table>,
detail::is_basic_value<typename Table::mapped_type>>::value,
decltype(::toml::get<T>(std::declval<typename Table::mapped_type &&>()))>
find(typename std::remove_reference<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<T>(std::move(tab.at(ky)));
}
// ----------------------------------------------------------------------------
// these overloads do not require to set T. and returns value itself.
template<typename C,
@ -869,107 +827,6 @@ find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ===========================================================================
// find_or(table, key, opt)
// ---------------------------------------------------------------------------
// exact types (return type can be a reference)
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>,
detail::is_exact_toml_type<T, typename Table::mapped_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<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>,
detail::is_exact_toml_type<T, typename Table::mapped_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<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>,
detail::is_exact_toml_type<T, typename Table::mapped_type>
>::value, T>&&
find_or(typename std::remove_reference<Table>::type&& tab, const key& ky, T&& opt)
{
if(tab.count(ky) == 0) {return opt;}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// std::string (return type can be a reference)
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>,
std::is_same<T, std::string>
>::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<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>,
std::is_same<T, std::string>
>::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<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>,
std::is_same<T, std::string>
>::value, std::string>
find_or(Table&& tab, const key& ky, T&& opt)
{
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// string literal (deduced as std::string)
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>,
detail::is_basic_value<typename Table::mapped_type>,
detail::is_string_literal<typename std::remove_reference<T>::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<T>(opt));
}
// ---------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>,
detail::is_basic_value<typename Table::mapped_type>,
detail::negation<detail::is_exact_toml_type<T, typename Table::mapped_type>>,
detail::negation<std::is_same<T, std::string>>,
detail::negation<detail::is_string_literal<typename std::remove_reference<T>::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<T>(opt));
}
// ============================================================================
// expect