mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6185dfee14 | ||
|
|
a74ad23514 | ||
|
|
2d9b4992ec | ||
|
|
82e8c1e68b | ||
|
|
46be054ce9 | ||
|
|
789d784769 | ||
|
|
81deb8efde | ||
|
|
072dccd05d | ||
|
|
637c99d637 | ||
|
|
0f48852730 | ||
|
|
0499b2907d | ||
|
|
61e69c9251 | ||
|
|
4a560ea1e5 | ||
|
|
c5b6ee6f81 | ||
|
|
1a7bf63622 | ||
|
|
8847cdc0a9 | ||
|
|
c82e76a111 | ||
|
|
4db486d76d | ||
|
|
91966a6917 | ||
|
|
b3917aaadf | ||
|
|
ba307003c4 | ||
|
|
21fd1271d9 | ||
|
|
f9ab7d6f56 | ||
|
|
0a3a41a708 | ||
|
|
6c2a536fa5 | ||
|
|
26eced3640 | ||
|
|
6f950c9ec8 | ||
|
|
ea13e40889 | ||
|
|
595fb1aef3 | ||
|
|
18986978fb | ||
|
|
c3cb22a789 | ||
|
|
5aebd6b562 | ||
|
|
4c13085b35 | ||
|
|
8709e8a14e | ||
|
|
9eea46ec01 | ||
|
|
2e9f937c43 | ||
|
|
65b10b6537 | ||
|
|
b51a8d5966 | ||
|
|
55e3d70869 | ||
|
|
20ba57e389 | ||
|
|
39bc3c64fe | ||
|
|
40ccf1d912 | ||
|
|
982ae36428 | ||
|
|
d6714ec450 | ||
|
|
773c3816be | ||
|
|
1b417ddc7a | ||
|
|
7a0ecf977d | ||
|
|
aade704411 | ||
|
|
ca3f6102ef | ||
|
|
4a58b629ce | ||
|
|
3adba237b8 | ||
|
|
ccf03d9291 | ||
|
|
30ae90ebd5 | ||
|
|
d5369c3429 | ||
|
|
48f2f0555d | ||
|
|
f40fd12e25 | ||
|
|
65c2c3c238 | ||
|
|
891a61a5e3 | ||
|
|
1e6f30f6fa | ||
|
|
02346a3126 | ||
|
|
1908f18e95 | ||
|
|
3bfa7f09ba | ||
|
|
243f43fafd | ||
|
|
66e27a94b6 | ||
|
|
227688ec63 | ||
|
|
e761a503c0 | ||
|
|
209ad79a8f | ||
|
|
cdf209d7f6 | ||
|
|
77ab391885 | ||
|
|
6628fe5ace | ||
|
|
f3e3000d45 | ||
|
|
f7380c6e32 | ||
|
|
d86870e038 | ||
|
|
0908806915 | ||
|
|
d17c192681 | ||
|
|
cad8f51256 | ||
|
|
43014c6619 | ||
|
|
30a41aa710 | ||
|
|
04bfeba3f2 | ||
|
|
190636b791 | ||
|
|
31e450f9af | ||
|
|
b1b72a94a8 | ||
|
|
6929bcdf78 | ||
|
|
fd063af7ce | ||
|
|
df6dcbc4ed | ||
|
|
76863cb27f | ||
|
|
514df99e40 | ||
|
|
055353a460 | ||
|
|
c4c416e8b2 | ||
|
|
6693ec78f4 | ||
|
|
dc112bd6c1 |
59
.circleci/config.yml
Normal file
59
.circleci/config.yml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
version: 2.1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test_suite:
|
||||||
|
environment:
|
||||||
|
- GOPATH: /home/circleci/go
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.9
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
command: |
|
||||||
|
g++ --version
|
||||||
|
cd tests/
|
||||||
|
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test
|
||||||
|
go get github.com/BurntSushi/toml-test
|
||||||
|
$GOPATH/bin/toml-test ./check_toml_test
|
||||||
|
output_result:
|
||||||
|
docker:
|
||||||
|
- image: circleci/buildpack-deps:bionic
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
command: |
|
||||||
|
g++ --version
|
||||||
|
cd tests/
|
||||||
|
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check.cpp -o check
|
||||||
|
git clone https://github.com/BurntSushi/toml-test.git
|
||||||
|
cp check toml-test/tests/invalid
|
||||||
|
cp check toml-test/tests/valid
|
||||||
|
cd toml-test/tests/invalid
|
||||||
|
for f in $(ls ./*.toml);
|
||||||
|
do echo "==> ${f}";
|
||||||
|
cat ${f};
|
||||||
|
echo "---------------------------------------";
|
||||||
|
./check ${f} invalid;
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "=======================================";
|
||||||
|
done
|
||||||
|
cd ../valid
|
||||||
|
for f in $(ls ./*.toml);
|
||||||
|
do echo "==> ${f}";
|
||||||
|
cat ${f};
|
||||||
|
echo "---------------------------------------";
|
||||||
|
./check ${f} valid;
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "=======================================";
|
||||||
|
done
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2.1
|
||||||
|
test:
|
||||||
|
jobs:
|
||||||
|
- test_suite
|
||||||
|
- output_result
|
||||||
629
README.md
629
README.md
@@ -1,74 +1,125 @@
|
|||||||
toml11
|
toml11
|
||||||
======
|
======
|
||||||
|
|
||||||
[](https://travis-ci.org/ToruNiina/toml11)
|
[](https://travis-ci.org/ToruNiina/toml11)
|
||||||
[](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master)
|
[](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master)
|
||||||
|
[](https://circleci.com/gh/ToruNiina/toml11/tree/master)
|
||||||
[](https://github.com/ToruNiina/toml11/releases)
|
[](https://github.com/ToruNiina/toml11/releases)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://doi.org/10.5281/zenodo.1209136)
|
[](https://doi.org/10.5281/zenodo.1209136)
|
||||||
|
|
||||||
C++11 header-only toml parser/encoder depending only on C++ standard library.
|
toml11 is a C++11 header-only toml parser/encoder depending only on C++ standard library.
|
||||||
|
|
||||||
compatible to the latest version of
|
compatible to the latest version of
|
||||||
[TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md)
|
[TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md)
|
||||||
after version 2.0.0.
|
after version 2.0.0.
|
||||||
|
|
||||||
Are you looking for pre-C++11 compatible toml parser?
|
It passes [the language agnostic test suite for TOML parsers by BurntSushi](https://github.com/BurntSushi/toml-test).
|
||||||
Try [Boost.toml](https://github.com/ToruNiina/Boost.toml)!
|
Not only the test suite itself, a TOML reader/encoder also runs on [CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||||
It has almost the same functionality as this library and works with C++98 & Boost.
|
You can see the error messages about invalid files and serialization results of valid files at
|
||||||
|
[CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||||
|
|
||||||
## How to use
|
## Example
|
||||||
|
|
||||||
## Installation
|
```cpp
|
||||||
|
#include <toml11/toml.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const auto data = toml::parse("example.toml");
|
||||||
|
|
||||||
|
// title = "an example toml file"
|
||||||
|
std::string title = toml::get<std::string>(data.at("title"));
|
||||||
|
std::cout << "the title is " << title << std::endl;
|
||||||
|
|
||||||
|
// nums = [1, 2, 3, 4, 5]
|
||||||
|
std::vector<int> nums = toml::get<std::vector<int>>(data.at("nums"));
|
||||||
|
std::cout << "the length of `nums` is" << nums.size() << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Integration](#integration)
|
||||||
|
- [Decoding a toml file](#decoding-a-toml-file)
|
||||||
|
- [In the case of syntax error](#in-the-case-of-syntax-error)
|
||||||
|
- [Getting a toml value](#getting-a-toml-value)
|
||||||
|
- [In the case of type error](#in-the-case-of-type-error)
|
||||||
|
- [Getting an array](#getting-an-array)
|
||||||
|
- [Getting a table](#getting-a-table)
|
||||||
|
- [Dotted keys](#dotted-keys)
|
||||||
|
- [Getting an array of tables](#getting-an-array-of-tables)
|
||||||
|
- [Cost of conversion](#cost-of-conversion)
|
||||||
|
- [Getting datetime and its variants](#getting-datetime-and-its-variants)
|
||||||
|
- [Getting with a fallback](#getting-with-a-fallback)
|
||||||
|
- [Expecting conversion](#expecting-conversion)
|
||||||
|
- [Finding a value from a table](#finding-a-value-from-a-table)
|
||||||
|
- [Checking value type](#checking-value-type)
|
||||||
|
- [Visiting a toml::value](#visiting-a-tomlvalue)
|
||||||
|
- [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)
|
||||||
|
- [Formatting user-defined error messages](#formatting-user-defined-error-messages)
|
||||||
|
- [Serializing TOML data](#serializing-toml-data)
|
||||||
|
- [Underlying types](#underlying-types)
|
||||||
|
- [Running Tests](#running-tests)
|
||||||
|
- [Contributors](#contributors)
|
||||||
|
- [Licensing Terms](#licensing-terms)
|
||||||
|
|
||||||
|
## Integration
|
||||||
|
|
||||||
Just include the file after adding it to the include path.
|
Just include the file after adding it to the include path.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <toml11/toml.hpp> // that's all! now you can use it.
|
#include <toml11/toml.hpp> // that's all! now you can use it.
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
const auto data = toml::parse("example.toml");
|
const auto data = toml::parse("example.toml");
|
||||||
const auto title = toml::get<std::string>(data.at("title"));
|
const auto title = toml::get<std::string>(data.at("title"));
|
||||||
std::cout << "the title is " << title << std::endl;
|
std::cout << "the title is " << title << std::endl;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Decoding toml file
|
## Decoding a toml file
|
||||||
|
|
||||||
The only thing you have to do is to pass a filename to the `toml::parse` function.
|
To parse a toml file, the only thing you have to do is
|
||||||
|
to pass a filename to the `toml::parse` function.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const std::string fname("sample.toml");
|
const std::string fname("sample.toml");
|
||||||
const toml::table data = toml::parse(fname);
|
const toml::table data = toml::parse(fname);
|
||||||
```
|
```
|
||||||
|
|
||||||
In the case of file open error, it will throw `std::runtime_error`.
|
If it encounters a file open error, it will throw `std::runtime_error`.
|
||||||
|
|
||||||
You can also pass a `stream` to the `toml::parse` function after checking the status.
|
You can also pass a `std::istream` to the `toml::parse` function.
|
||||||
|
To show a filename in an error message, it is recommended to pass the filename
|
||||||
Note that on __Windows OS__, stream that is opened as text-mode automatically converts
|
with the stream.
|
||||||
CRLF ("\r\n") into LF ("\n") and this leads inconsistency between file size and
|
|
||||||
the contents that would be read. This causes weird error. To use a file stream
|
|
||||||
with `toml::parse`, don't forget to pass binary mode flag when you open the
|
|
||||||
stream.
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::ifstream ifs("sample.toml", std::ios_base::binary);
|
std::ifstream ifs("sample.toml", std::ios_base::binary);
|
||||||
assert(ifs.good());
|
assert(ifs.good());
|
||||||
const auto data = toml::parse(ifs /*, "filename" (optional)*/);
|
const auto data = toml::parse(ifs, /*optional*/ "sample.toml");
|
||||||
```
|
```
|
||||||
|
|
||||||
To show a better error message, it is recommended to pass a filename with `istream`.
|
Note that on Windows, if a file is opened in text-mode, CRLF ("\r\n") will
|
||||||
See also [in the case of syntax error](#in-the-case-of-syntax-error)
|
automatically be converted to LF ("\n") and this causes inconsistency between
|
||||||
and [passing invalid type to toml::get](#passing-invalid-type-to-tomlget).
|
file size and the contents that would be read. This causes weird error.
|
||||||
|
To use a file stream with `toml::parse` on Windows, don't forget to open it
|
||||||
|
in binary mode.
|
||||||
|
|
||||||
### In the case of syntax error
|
### In the case of syntax error
|
||||||
|
|
||||||
If there is a syntax error in a toml file, `toml::parse` will throw `toml::syntax_error`.
|
If there is a syntax error in a toml file, `toml::parse` will throw `toml::syntax_error`.
|
||||||
|
|
||||||
toml11 now has clean and informative error messages inspired by Rust and
|
toml11 has clean and informative error messages inspired by Rust and
|
||||||
it looks like the following (comment after hash sign are actually not shown).
|
it looks like the following.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
terminate called after throwing an instance of 'toml::syntax_error'
|
terminate called after throwing an instance of 'toml::syntax_error'
|
||||||
@@ -78,8 +129,8 @@ terminate called after throwing an instance of 'toml::syntax_error'
|
|||||||
| ^------ expected newline, but got '='. # error reason
|
| ^------ expected newline, but got '='. # error reason
|
||||||
```
|
```
|
||||||
|
|
||||||
If you (mistakenly) duplicate tables and got an error, you may want to see
|
If you (mistakenly) duplicate tables and got an error, it is helpful to see
|
||||||
where the other is. toml11 shows both at the same time.
|
where they are. toml11 shows both at the same time like the following.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
terminate called after throwing an instance of 'toml::syntax_error'
|
terminate called after throwing an instance of 'toml::syntax_error'
|
||||||
@@ -93,15 +144,16 @@ terminate called after throwing an instance of 'toml::syntax_error'
|
|||||||
```
|
```
|
||||||
|
|
||||||
Since the error message generation is generally a difficult task, the current
|
Since the error message generation is generally a difficult task, the current
|
||||||
status is not ideal. toml11 needs your help. If you encounter a weird error message,
|
status is not ideal. If you encounter a weird error message, please let us know
|
||||||
please let us know and contribute to improve the quality!
|
and contribute to improve the quality!
|
||||||
|
|
||||||
### Getting a toml value
|
## Getting a toml value
|
||||||
|
|
||||||
After parsing successfully, you can obtain the values from the result of
|
After parsing successfully, you can obtain the values from the result of
|
||||||
`toml::parse` (here, `data`) using `toml::get` function.
|
`toml::parse` using `toml::get` function.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
# sample.toml
|
||||||
answer = 42
|
answer = 42
|
||||||
pi = 3.14
|
pi = 3.14
|
||||||
numbers = [1,2,3]
|
numbers = [1,2,3]
|
||||||
@@ -111,6 +163,7 @@ key = "value"
|
|||||||
```
|
```
|
||||||
|
|
||||||
``` cpp
|
``` cpp
|
||||||
|
const auto data = toml::parse("sample.toml");
|
||||||
const auto answer = toml::get<std::int64_t >(data.at("answer"));
|
const auto answer = toml::get<std::int64_t >(data.at("answer"));
|
||||||
const auto pi = toml::get<double >(data.at("pi"));
|
const auto pi = toml::get<double >(data.at("pi"));
|
||||||
const auto numbers = toml::get<std::vector<int>>(data.at("numbers"));
|
const auto numbers = toml::get<std::vector<int>>(data.at("numbers"));
|
||||||
@@ -120,20 +173,24 @@ const auto key = toml::get<std::string>( tab.at("key"));
|
|||||||
```
|
```
|
||||||
|
|
||||||
When you pass an exact TOML type that does not require type conversion,
|
When you pass an exact TOML type that does not require type conversion,
|
||||||
`toml::get` returns also a reference through which you can modify the content.
|
`toml::get` returns a reference through which you can modify the content.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
toml::get<toml::integer>(data["answer"]) = 6 * 9;
|
auto data = toml::parse("sample.toml");
|
||||||
|
auto& answer = toml::get<toml::integer>(data["answer"]); // get reference
|
||||||
|
answer = 6 * 9; // write to data.answer
|
||||||
std::cout << toml::get<int>(data.at("answer")) << std::endl; // 54
|
std::cout << toml::get<int>(data.at("answer")) << std::endl; // 54
|
||||||
```
|
```
|
||||||
|
|
||||||
If the specified type requires conversion, you can't take a reference to the value.
|
If the specified type requires conversion, you can't take a reference to the value.
|
||||||
See also [underlying types](#underlying-types).
|
See also [underlying types](#underlying-types).
|
||||||
|
|
||||||
#### Passing invalid type to toml::get
|
NOTE: To enable to get a reference, conversions between Float and Integer are not supported.
|
||||||
|
|
||||||
If you choose the invalid type, `toml::type_error` will be thrown.
|
### In the case of type error
|
||||||
Similar to the `syntax_error`, toml11 also displays informative error messages.
|
|
||||||
|
If you pass an invalid type to `toml::get`, `toml::type_error` will be thrown.
|
||||||
|
Similar to the case of syntax error, toml11 also displays clean error messages.
|
||||||
The error message when you choose `int` to get `string` value would be like this.
|
The error message when you choose `int` to get `string` value would be like this.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
@@ -144,15 +201,21 @@ terminate called after throwing an instance of 'toml::type_error'
|
|||||||
| ~~~~~~~~~~~~~~ the actual type is string
|
| ~~~~~~~~~~~~~~ the actual type is string
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: In order to show this kind of error message, all the toml values have 1
|
NOTE: In order to show this kind of error message, all the toml values have
|
||||||
`shared_ptr` that points the corresponding byte sequence and 2 iterators that point the range.
|
pointers to represent its range in a file. The entire contents of a file is
|
||||||
It is recommended to destruct all the `toml::value` classes after configuring your application to save memory resources.
|
shared by `toml::value`s and remains on the heap memory. It is recommended to
|
||||||
|
destruct all the `toml::value` classes after configuring your application
|
||||||
|
if you have a large TOML file compared to the memory resource.
|
||||||
|
|
||||||
### Getting arrays
|
## Getting an array
|
||||||
|
|
||||||
You can set any kind of `container` class to obtain a `toml::array` except for `map`-like classes.
|
You can get any kind of `container` class from a `toml::array`
|
||||||
|
except for `map`-like classes.
|
||||||
|
|
||||||
``` cpp
|
``` cpp
|
||||||
|
// # sample.toml
|
||||||
|
// numbers = [1,2,3]
|
||||||
|
|
||||||
const auto vc = toml::get<std::vector<int> >(data.at("numbers"));
|
const auto vc = toml::get<std::vector<int> >(data.at("numbers"));
|
||||||
const auto ls = toml::get<std::list<int> >(data.at("numbers"));
|
const auto ls = toml::get<std::list<int> >(data.at("numbers"));
|
||||||
const auto dq = toml::get<std::deque<int> >(data.at("numbers"));
|
const auto dq = toml::get<std::deque<int> >(data.at("numbers"));
|
||||||
@@ -161,16 +224,16 @@ const auto ar = toml::get<std::array<int, 3>>(data.at("numbers"));
|
|||||||
// it will throw toml::type_error because std::array is not resizable.
|
// it will throw toml::type_error because std::array is not resizable.
|
||||||
```
|
```
|
||||||
|
|
||||||
Surprisingly, you can also get a `toml::array` as `std::pair` and `std::tuple.`
|
Surprisingly, you can also get `std::pair`s and `std::tuple`s from `toml::array`.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const auto tp = toml::get<std::tuple<short, int, unsigned int>>(data.at("numbers"));
|
const auto tp = toml::get<std::tuple<short, int, unsigned int>>(data.at("numbers"));
|
||||||
```
|
```
|
||||||
|
|
||||||
The case when you need this functionality is to get an array of arrays.
|
This functionality is helpful when you have the following toml file.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
aofa = [[1,2,3], ["foo", "bar", "baz"]] # toml allows this
|
array_of_arrays = [[1, 2, 3], ["foo", "bar", "baz"]] # toml allows this
|
||||||
```
|
```
|
||||||
|
|
||||||
What is the corresponding C++ type? Obviously, it is a `std::pair` of `std::vector`s.
|
What is the corresponding C++ type? Obviously, it is a `std::pair` of `std::vector`s.
|
||||||
@@ -178,21 +241,21 @@ What is the corresponding C++ type? Obviously, it is a `std::pair` of `std::vect
|
|||||||
```cpp
|
```cpp
|
||||||
const auto aofa = toml::get<
|
const auto aofa = toml::get<
|
||||||
std::pair<std::vector<int>, std::vector<std::string>>
|
std::pair<std::vector<int>, std::vector<std::string>>
|
||||||
>(data.at("aofa"));
|
>(data.at("array_of_arrays"));
|
||||||
```
|
```
|
||||||
|
|
||||||
If you don't know what the type is inside the array, you can use `toml::array`,
|
If you don't know the type of the elements, you can use `toml::array`,
|
||||||
which is a `std::vector` of `toml::value`, instead.
|
which is a `std::vector` of `toml::value`, instead.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const auto aofa = toml::get<toml::array>(data.at("aofa"));
|
const auto aofa = toml::get<toml::array>(data.at("array_of_arrays"));
|
||||||
const auto first = toml::get<toml::array>(aofa.at(0));
|
const auto first = toml::get<std::vector<int>>(aofa.at(0));
|
||||||
```
|
```
|
||||||
|
|
||||||
See also [expecting conversion](#expecting-conversion)
|
See also [expecting conversion](#expecting-conversion)
|
||||||
and [checking-value-type](#checking-value-type).
|
and [checking-value-type](#checking-value-type).
|
||||||
|
|
||||||
### Getting tables
|
## Getting a table
|
||||||
|
|
||||||
`toml::table` is a key component of this library, which is an alias of
|
`toml::table` is a key component of this library, which is an alias of
|
||||||
a `std::unordered_map` from `toml::key (a.k.a. std::string)` to `toml::value`.
|
a `std::unordered_map` from `toml::key (a.k.a. std::string)` to `toml::value`.
|
||||||
@@ -219,12 +282,13 @@ key2 = "bar" # toml String
|
|||||||
```
|
```
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
const auto data = toml::parse("sample.toml");
|
||||||
const auto tab = toml::get<std::map<std::string, std::string>>(data.at("tab"));
|
const auto tab = toml::get<std::map<std::string, std::string>>(data.at("tab"));
|
||||||
std::cout << tab["key1"] << std::endl; // foo
|
std::cout << tab["key1"] << std::endl; // foo
|
||||||
std::cout << tab["key2"] << std::endl; // bar
|
std::cout << tab["key2"] << std::endl; // bar
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dotted keys
|
## Dotted keys
|
||||||
|
|
||||||
TOML v0.5.0 has a new feature named "dotted keys".
|
TOML v0.5.0 has a new feature named "dotted keys".
|
||||||
You can chain keys to represent the structure of the data.
|
You can chain keys to represent the structure of the data.
|
||||||
@@ -249,41 +313,49 @@ const auto physical = toml::get<toml::table>(data.at("physical"));
|
|||||||
const auto color = toml::get<std::string>(physical.at("color"));
|
const auto color = toml::get<std::string>(physical.at("color"));
|
||||||
```
|
```
|
||||||
|
|
||||||
### An array of tables
|
## Getting an array of tables
|
||||||
|
|
||||||
An array of tables is just an array of tables.
|
An array of tables is just an array of tables.
|
||||||
You can get it completely in the same way as the other arrays and tables.
|
You can get it completely in the same way as the other arrays and tables.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
array_of_inline_table = [{key = "value1"}, {key = "value2"}, {key = "value3"}]
|
# sample.toml
|
||||||
|
array_of_inline_tables = [{key = "value1"}, {key = "value2"}, {key = "value3"}]
|
||||||
|
|
||||||
[[array_of_table]]
|
[[array_of_tables]]
|
||||||
key = "value4"
|
key = "value4"
|
||||||
[[array_of_table]]
|
[[array_of_tables]]
|
||||||
key = "value5"
|
key = "value5"
|
||||||
[[array_of_table]]
|
[[array_of_tables]]
|
||||||
key = "value6"
|
key = "value6"
|
||||||
```
|
```
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const auto aot1 = toml::get<std::vector<toml::table>>(data.at("array_of_inline_table"));
|
const auto data = toml::parse("sample.toml");
|
||||||
const auto aot2 = toml::get<std::vector<toml::table>>(data.at("array_of_table"));
|
const auto aot1 = toml::get<std::vector<toml::table>>(data.at("array_of_inline_tables"));
|
||||||
|
const auto aot2 = toml::get<std::vector<toml::table>>(data.at("array_of_tables"));
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cost of conversion
|
## Cost of conversion
|
||||||
|
|
||||||
Although `toml::get` is convenient, it has additional copy-cost because
|
Although `toml::get` is convenient, it has additional copy-cost because
|
||||||
it copies data contained in `toml::value` to the user-specified type.
|
it copies data contained in `toml::value` to the user-specified type.
|
||||||
Of course in some case this overhead is not ignorable.
|
Of course in some cases this overhead is not ignorable.
|
||||||
|
|
||||||
By passing the exact types, `toml::get` returns reference that has nealy zero overhead.
|
```cpp
|
||||||
|
// the following code constructs a std::vector.
|
||||||
|
// it requires heap allocation for vector and element conversion.
|
||||||
|
const auto array = toml::get<std::vector<int>>(data.at("foo"));
|
||||||
|
```
|
||||||
|
|
||||||
|
By passing the exact types, `toml::get` returns reference that has no overhead.
|
||||||
|
|
||||||
``` cpp
|
``` cpp
|
||||||
const auto& tab = toml::get<toml::array>(data.at("tab"));
|
const auto& tab = toml::get<toml::array>(data.at("tab"));
|
||||||
const auto& numbers = toml::get<toml::table>(data.at("numbers"));
|
const auto& numbers = toml::get<toml::table>(data.at("numbers"));
|
||||||
```
|
```
|
||||||
|
|
||||||
Unfortunately, in this case you need to call `toml::get` each time you access to
|
In this case you need to call `toml::get` each time you access to
|
||||||
the element of `toml::array` because `toml::array` is an array of `toml::value`.
|
the element of `toml::array` because `toml::array` is an array of `toml::value`.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -292,34 +364,61 @@ const auto& num1 = toml::get<toml::integer>(numbers.at(1));
|
|||||||
const auto& num2 = toml::get<toml::integer>(numbers.at(2));
|
const auto& num2 = toml::get<toml::integer>(numbers.at(2));
|
||||||
```
|
```
|
||||||
|
|
||||||
### Datetime and its variants
|
## Getting datetime and its variants
|
||||||
|
|
||||||
TOML v0.5.0 has 4 different datetime objects, `local_date`, `local_time`,
|
TOML v0.5.0 has 4 different datetime objects, `local_date`, `local_time`,
|
||||||
`local_datetime`, and `offset_datetime`. With toml11, you can convert `local_time`
|
`local_datetime`, and `offset_datetime`.
|
||||||
to your favorite `std::chrono::duration` and others to `std::chrono::system_clock::time_point`.
|
|
||||||
|
Since `local_date`, `local_datetime`, and `offset_datetime` represent a time
|
||||||
|
point, you can convert them to `std::chrono::system_clock::time_point`.
|
||||||
|
|
||||||
|
Contrary, `local_time` does not represents a time point because they lack a
|
||||||
|
date information, but it can be converted to `std::chrono::duration` that
|
||||||
|
represents a duration from the beginning of the day, `00:00:00.000`.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
time = 12:30:00
|
|
||||||
date = 2018-12-23
|
date = 2018-12-23
|
||||||
|
time = 12:30:00
|
||||||
|
l_dt = 2018-12-23T12:30:00
|
||||||
|
o_dt = 2018-12-23T12:30:00+09:30
|
||||||
```
|
```
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const auto dur = toml::get<std::chrono::minutes>(data.at("time")); // 12 * 60 + 30 min
|
const auto data = toml::parse("sample.toml");
|
||||||
const auto tp = toml::get<std::chrono::system_clock::time_point>(data.at("date"));
|
|
||||||
|
const auto date = toml::get<std::chrono::system_clock::time_point>(data.at("date"));
|
||||||
|
const auto l_dt = toml::get<std::chrono::system_clock::time_point>(data.at("l_dt"));
|
||||||
|
const auto o_dt = toml::get<std::chrono::system_clock::time_point>(data.at("o_dt"));
|
||||||
|
|
||||||
|
const auto time = toml::get<std::chrono::minutes>(data.at("time")); // 12 * 60 + 30 min
|
||||||
```
|
```
|
||||||
|
|
||||||
### Getting with a fallback
|
toml11 contains datetime as its own struct.
|
||||||
|
You can see the definitions in [toml/datetime.hpp](toml/datetime.hpp).
|
||||||
|
|
||||||
`toml::get_or` returns a default value if `toml::get<T>` failed.
|
## Getting with a fallback
|
||||||
|
|
||||||
|
`toml::get_or` returns a default value if `toml::get<T>` failed.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
toml::table data; // empty table!
|
toml::value v("foo"); // v contains String
|
||||||
const auto value = toml::get_or(data, "key", 42); // value => int 42.
|
const int value = toml::get_or(v, 42); // conversion fails. it returns 42.
|
||||||
```
|
```
|
||||||
|
|
||||||
`toml::get_or` automatically deduces what type you want to get from the default value you passed.
|
`toml::get_or` automatically deduces what type you want to get from
|
||||||
|
the default value you passed.
|
||||||
|
|
||||||
### Expecting conversion
|
To get a reference through this function, take care about the default value.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
toml::value v("foo"); // v contains String
|
||||||
|
toml::integer& i = toml::get_or(v, 42); // does not work because binding `42`
|
||||||
|
// to `integer&` is invalid
|
||||||
|
toml::integer opt = 42;
|
||||||
|
toml::integer& i = toml::get_or(v, opt); // this works.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expecting conversion
|
||||||
|
|
||||||
By using `toml::expect`, you will get your expected value or an error message
|
By using `toml::expect`, you will get your expected value or an error message
|
||||||
without throwing `toml::type_error`.
|
without throwing `toml::type_error`.
|
||||||
@@ -343,7 +442,7 @@ const auto value = toml::expect<int>(data.at("number"))
|
|||||||
}).unwrap_or(/*default value =*/ 3.14);
|
}).unwrap_or(/*default value =*/ 3.14);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Finding value from table
|
## Finding a value from a table
|
||||||
|
|
||||||
toml11 provides utility function to find a value from `toml::table`.
|
toml11 provides utility function to find a value from `toml::table`.
|
||||||
Of course, you can do this in your own way with `toml::get` because
|
Of course, you can do this in your own way with `toml::get` because
|
||||||
@@ -354,7 +453,7 @@ const auto data = toml::parse("example.toml");
|
|||||||
const auto num = toml::find<int>(data, "num", /*for err msg*/"example.toml");
|
const auto num = toml::find<int>(data, "num", /*for err msg*/"example.toml");
|
||||||
```
|
```
|
||||||
|
|
||||||
If the value does not exist, it throws `std::out_of_range` with informative error message.
|
If the value does not exist, it throws `std::out_of_range` with an error message.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
terminate called after throwing an instance of 'std::out_of_range'
|
terminate called after throwing an instance of 'std::out_of_range'
|
||||||
@@ -373,7 +472,8 @@ const auto num = toml::find<int>(data.at("table"), "num");
|
|||||||
```
|
```
|
||||||
|
|
||||||
In this case, because the value `data.at("table")` knows the locatoin of itself,
|
In this case, because the value `data.at("table")` knows the locatoin of itself,
|
||||||
you don't need to pass where you find the value. `toml::find` will show you a great error message.
|
you don't need to pass where you find the value.
|
||||||
|
`toml::find` will show you an error message including table location.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
terminate called after throwing an instance of 'std::out_of_range'
|
terminate called after throwing an instance of 'std::out_of_range'
|
||||||
@@ -385,47 +485,70 @@ terminate called after throwing an instance of 'std::out_of_range'
|
|||||||
|
|
||||||
If it's not a `toml::table`, the same error as "invalid type" would be thrown.
|
If it's not a `toml::table`, the same error as "invalid type" would be thrown.
|
||||||
|
|
||||||
### Checking value type
|
There is another utility function, `toml::find_or`.
|
||||||
|
It is almost same as `toml::find`, but returns a default value if the value is
|
||||||
|
not found or has a different type, like `toml::get_or`.
|
||||||
|
|
||||||
When you don't know the exact type of toml-value, you can get `enum` type from `toml::value`.
|
```cpp
|
||||||
|
const auto data = toml::parse("example.toml");
|
||||||
|
const auto num = toml::find_or(data.at("table"), "num", 42);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Checking value type
|
||||||
|
|
||||||
|
You can check what type of value does `toml::value` contains by `is_*` function.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
toml::value v = /* ... */;
|
||||||
|
if(v.is_integer() && toml::get<int>(v) == 42)
|
||||||
|
{
|
||||||
|
std::cout << "value is 42" << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The complete list of the functions is below.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const toml::value v(/*...*/);
|
||||||
|
v.is_boolean();
|
||||||
|
v.is_integer();
|
||||||
|
v.is_float();
|
||||||
|
v.is_string();
|
||||||
|
v.is_offset_datetime();
|
||||||
|
v.is_local_datetime();
|
||||||
|
v.is_local_date();
|
||||||
|
v.is_local_time();
|
||||||
|
v.is_array();
|
||||||
|
v.is_table();
|
||||||
|
v.is_uninitialized();
|
||||||
|
```
|
||||||
|
|
||||||
|
Also, you can get `enum class` value from `toml::value`.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
switch(data.at("something").type())
|
switch(data.at("something").type())
|
||||||
{
|
{
|
||||||
case toml::value_t::Integer: /* do some stuff */; break;
|
case toml::value_t::Integer: /*do some stuff*/ ; break;
|
||||||
case toml::value_t::Float : /* do some stuff */; break;
|
case toml::value_t::Float : /*do some stuff*/ ; break;
|
||||||
case toml::value_t::String : /* do some stuff */; break;
|
case toml::value_t::String : /*do some stuff*/ ; break;
|
||||||
default : throw std::runtime_error(
|
default : throw std::runtime_error(
|
||||||
"unexpected type : " + toml::stringize(data.at("something").type()));
|
"unexpected type : " + toml::stringize(data.at("something").type()));
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fill only the matched value
|
The complete list of the `enum`s can be found in the section
|
||||||
|
[underlying types](#underlying-types).
|
||||||
|
|
||||||
The more sophisticated way is using `toml::from_toml` and `std::tie`.
|
The `enum`s can be used as a parameter of `toml::value::is` function like the following.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
toml::table data{{"something", toml::value("foo")}};
|
toml::value v = /* ... */;
|
||||||
int i = 0;
|
if(v.is(toml::value_t::Boolean)) // ...
|
||||||
double d = 0.;
|
|
||||||
std::string s;
|
|
||||||
toml::from_toml(std::tie(i, d, s), data.at("something"));
|
|
||||||
std::cout << i << ", " << d << ", " << s << std::endl; // 0, 0, foo
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, only matched value will be filled. The others are left intact after calling `from_toml`.
|
## Visiting a toml::value
|
||||||
It should be noted that `toml::from_toml` returns as usual even if there are no matched type.
|
|
||||||
|
|
||||||
`from_toml` can be used also for single type.
|
toml11 provides `toml::visit` to apply a function to `toml::value` in the
|
||||||
|
|
||||||
```cpp
|
|
||||||
int i = 0;
|
|
||||||
toml::from_toml(i, data.at("something"));
|
|
||||||
```
|
|
||||||
|
|
||||||
### visiting toml::value
|
|
||||||
|
|
||||||
TOML v2.1.0+ provides `toml::visit` to apply a function to `toml::value` in the
|
|
||||||
same way as `std::variant`.
|
same way as `std::variant`.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -439,29 +562,223 @@ The function object that would be passed to `toml::visit` must be able to
|
|||||||
recieve all the possible TOML types. Also, the result types should be the same
|
recieve all the possible TOML types. Also, the result types should be the same
|
||||||
each other.
|
each other.
|
||||||
|
|
||||||
### Sanitizing UTF-8 codepoints
|
## TOML literal
|
||||||
|
|
||||||
toml11 shows warning if a value of an escape sequence used
|
toml11 supports `"..."_toml` literal.
|
||||||
to represent unicode character exceeds the unicode range.
|
It accept both a bare value and a file content.
|
||||||
|
|
||||||
```console
|
```cpp
|
||||||
[warning] input codepoint (0011FFFF) is too large to decode as a unicode character. The result may not be able to render to your screen.
|
using namespace toml::literals::toml_literals;
|
||||||
--> example.toml
|
|
||||||
3 | exceeds_unicode = "\U0011FFFF example"
|
// `_toml` can convert a bare value without key
|
||||||
| ~~~~~~~~~ should be in [0x00..0x10FFFF]
|
const toml::value v = u8"0xDEADBEEF"_toml;
|
||||||
|
// v is an Integer value containing 0xDEADBEEF.
|
||||||
|
|
||||||
|
// raw string literal (`R"(...)"` is useful for this purpose)
|
||||||
|
const toml::value t = u8R"(
|
||||||
|
title = "this is TOML literal"
|
||||||
|
[table]
|
||||||
|
key = "value"
|
||||||
|
)"_toml;
|
||||||
|
// the literal will be parsed and the result will be contained in t
|
||||||
```
|
```
|
||||||
|
|
||||||
Also, toml11 throws `std::domain_error` if the code point exceeds the range that can be represented by utf-8.
|
The literal function is defined in the same way as the standard library literals
|
||||||
|
such as `std::literals::string_literals::operator""s`.
|
||||||
|
|
||||||
```console
|
```cpp
|
||||||
terminate called after throwing an instance of 'std::range_error'
|
namespace toml
|
||||||
what(): [error] input codepoint (0020FFFF) is too large to encode as utf-8.
|
{
|
||||||
--> example.toml
|
inline namespace literals
|
||||||
3 | exceeds_utf8 = "\U0020FFFF example"
|
{
|
||||||
| ~~~~~~~~~ should be in [0x00..0x10FFFF]
|
inline namespace toml_literals
|
||||||
|
{
|
||||||
|
toml::value operator""_toml(const char* str, std::size_t len);
|
||||||
|
|
||||||
|
} // toml_literals
|
||||||
|
} // literals
|
||||||
|
} // toml
|
||||||
```
|
```
|
||||||
|
|
||||||
### Formatting your error
|
Access to the operator can be gained with `using namespace toml::literals;`,
|
||||||
|
`using namespace toml::toml_literals`, and `using namespace toml::literals::toml_literals`.
|
||||||
|
|
||||||
|
Note that a key that is composed only of digits is allowed in TOML.
|
||||||
|
And, unlike the file parser, toml-literal allows a bare value without a key.
|
||||||
|
Thus it is difficult to distinguish arrays having integers and definitions of
|
||||||
|
tables that are named as digits.
|
||||||
|
Currently, literal `[1]` becomes a table named "1".
|
||||||
|
To ensure a literal to be considered as an array with one element, you need to
|
||||||
|
add a comma after the first element (like `[1,]`).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
"[1,2,3]"_toml; // This is an array
|
||||||
|
"[table]"_toml; // This is a table that has an empty table named "table" inside.
|
||||||
|
"[[1,2,3]]"_toml; // This is an array of arrays
|
||||||
|
"[[table]]"_toml; // This is a table that has an array of tables inside.
|
||||||
|
|
||||||
|
"[[1]]"_toml; // This literal is ambiguous.
|
||||||
|
// Currently, it becomes a table that has array of table "1".
|
||||||
|
"1 = [{}]"_toml; // This is a table that has an array of table named 1.
|
||||||
|
"[[1,]]"_toml; // This is an array of arrays.
|
||||||
|
"[[1],]"_toml; // ditto.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conversion between toml value and arbitrary types
|
||||||
|
|
||||||
|
You can also use `toml::get` and other related functions with the types you defined
|
||||||
|
after you implement some stuff.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace ext
|
||||||
|
{
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
std::string c;
|
||||||
|
};
|
||||||
|
} // ext
|
||||||
|
|
||||||
|
const auto data = toml::parse("example.toml");
|
||||||
|
|
||||||
|
const foo f = toml::get<ext::foo>(data.at("foo"));
|
||||||
|
```
|
||||||
|
|
||||||
|
There are 2 ways to use `toml::get` with the types that you defined.
|
||||||
|
|
||||||
|
The first one is to implement `from_toml(const toml::value&)` member function.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace ext
|
||||||
|
{
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
std::string c;
|
||||||
|
|
||||||
|
void from_toml(const toml::value& v)
|
||||||
|
{
|
||||||
|
this->a = toml::find<int >(v, "a");
|
||||||
|
this->b = toml::find<double >(v, "b");
|
||||||
|
this->c = toml::find<std::string>(v, "c");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // ext
|
||||||
|
```
|
||||||
|
|
||||||
|
In this way, because `toml::get` first constructs `foo` without arguments,
|
||||||
|
the type should be default-constructible.
|
||||||
|
|
||||||
|
The second is to implement specialization of `toml::from` for your type.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace ext
|
||||||
|
{
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
std::string c;
|
||||||
|
};
|
||||||
|
} // ext
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
struct from<ext::foo>
|
||||||
|
{
|
||||||
|
ext::foo from_toml(const toml::value& v)
|
||||||
|
{
|
||||||
|
ext::foo f;
|
||||||
|
f.a = toml::find<int >(v, "a");
|
||||||
|
f.b = toml::find<double >(v, "b");
|
||||||
|
f.c = toml::find<std::string>(v, "c");
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // toml
|
||||||
|
```
|
||||||
|
|
||||||
|
In this way, since the conversion function is defined outside of the class,
|
||||||
|
you can add conversion between `toml::value` and classes defined in another library.
|
||||||
|
|
||||||
|
Note that you cannot implement both of the functions because the overload
|
||||||
|
resolution of `toml::get` will be ambiguous.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
The opposite direction is also supported in a similar way. You can directly
|
||||||
|
pass your type to `toml::value`'s constructor by introducing `into_toml` or
|
||||||
|
`toml::into<T>`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace ext
|
||||||
|
{
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
std::string c;
|
||||||
|
|
||||||
|
toml::table into_toml() const // you need to mark it const.
|
||||||
|
{
|
||||||
|
return toml::table{{"a", this->a}, {"b", this->b}, {"c", this->c}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // ext
|
||||||
|
|
||||||
|
ext::foo f{42, 3.14, "foobar"};
|
||||||
|
toml::value v(f);
|
||||||
|
```
|
||||||
|
|
||||||
|
The definition of `toml::into<T>` is similar to `toml::from<T>`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace ext
|
||||||
|
{
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
std::string c;
|
||||||
|
};
|
||||||
|
} // ext
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
struct into<ext::foo>
|
||||||
|
{
|
||||||
|
toml::table into_toml(const ext::foo& f)
|
||||||
|
{
|
||||||
|
return toml::table{{"a", f.a}, {"b", f.b}, {"c", f.c}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // toml
|
||||||
|
|
||||||
|
ext::foo f{42, 3.14, "foobar"};
|
||||||
|
toml::value v(f);
|
||||||
|
```
|
||||||
|
|
||||||
|
Any type that can be converted to `toml::value`, e.g. `toml::table`, `toml::array`,
|
||||||
|
is okay to return from `into_toml`.
|
||||||
|
|
||||||
|
## Invalid UTF-8 codepoints
|
||||||
|
|
||||||
|
toml11 throws `syntax_error` if a value of an escape sequence
|
||||||
|
representing unicode character is not a valid UTF-8 codepoint.
|
||||||
|
|
||||||
|
```console
|
||||||
|
what(): [error] toml::read_utf8_codepoint: input codepoint is too large.
|
||||||
|
--> utf8.toml
|
||||||
|
1 | exceeds_unicode = "\U0011FFFF example"
|
||||||
|
| ^--------- should be in [0x00..0x10FFFF]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Formatting user-defined error messages
|
||||||
|
|
||||||
When you encounter an error after you read the toml value, you may want to
|
When you encounter an error after you read the toml value, you may want to
|
||||||
show the error with the value.
|
show the error with the value.
|
||||||
@@ -514,22 +831,18 @@ you will get an error message like this.
|
|||||||
| ~~ maximum number here
|
| ~~ maximum number here
|
||||||
```
|
```
|
||||||
|
|
||||||
### Serializing TOML data
|
## Serializing TOML data
|
||||||
|
|
||||||
toml11 v2.1.0 enables you to serialize data into toml format.
|
toml11 (after v2.1.0) enables you to serialize data into toml format.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const auto data = toml::table{{"foo", 42}, {"bar", "baz"}};
|
const auto data = toml::table{{"foo", 42}, {"bar", "baz"}};
|
||||||
|
|
||||||
const std::string serial = toml::format(data);
|
|
||||||
// serial == "{bar=\"baz\",foo=42}"
|
|
||||||
|
|
||||||
std::cout << data << std::endl;
|
std::cout << data << std::endl;
|
||||||
// bar = "baz"
|
// bar = "baz"
|
||||||
// foo = 42
|
// foo = 42
|
||||||
```
|
```
|
||||||
|
|
||||||
toml11 automatically makes a tiny table and array inline.
|
toml11 automatically makes a small table and small array inline.
|
||||||
You can specify the width to make them inline by `std::setw` for streams.
|
You can specify the width to make them inline by `std::setw` for streams.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -572,23 +885,8 @@ It is recommended to set width before printing data. Some I/O functions changes
|
|||||||
width to 0, and it makes all the stuff (including `toml::array`) multiline.
|
width to 0, and it makes all the stuff (including `toml::array`) multiline.
|
||||||
The resulting files becomes too long.
|
The resulting files becomes too long.
|
||||||
|
|
||||||
`toml::format` receives optional second argument to set the width.
|
|
||||||
By default, it is 80.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
const auto data = toml::table{
|
|
||||||
{"qux", toml::table{{"foo", 42}, {"bar", "baz"}}}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::string serial = toml::format(data, /*width = */ 0);
|
|
||||||
// [qux]
|
|
||||||
// bar = "baz"
|
|
||||||
// foo = 42
|
|
||||||
```
|
|
||||||
|
|
||||||
To control the precision of floating point numbers, you need to pass
|
To control the precision of floating point numbers, you need to pass
|
||||||
`std::setprecision` to stream or pass `int` to the optional third argument of
|
`std::setprecision` to stream.
|
||||||
`toml::format` (by default, it is `std::numeric_limits<double>::max_digit10`).
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const auto data = toml::table{
|
const auto data = toml::table{
|
||||||
@@ -601,8 +899,32 @@ std::cout << std::setprecision(17) << data << std::endl;
|
|||||||
std::cout << std::setprecision( 7) << data << std::endl;
|
std::cout << std::setprecision( 7) << data << std::endl;
|
||||||
// e = 2.718282
|
// e = 2.718282
|
||||||
// pi = 3.141593
|
// pi = 3.141593
|
||||||
|
```
|
||||||
|
|
||||||
const std::string serial = toml::format(data, /*width = */ 0, /*prec = */ 17);
|
There is another way to format toml values, `toml::format()`.
|
||||||
|
It returns `std::string` that represents a value.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const toml::value v{{"a", 42}};
|
||||||
|
const std::string fmt = toml::format(v);
|
||||||
|
// a = 42
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that since `toml::format` formats a value, the resulting string may lack
|
||||||
|
the key value.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const toml::value v{3.14};
|
||||||
|
const std::string fmt = toml::format(v);
|
||||||
|
// 3.14
|
||||||
|
```
|
||||||
|
|
||||||
|
To control the width and precision, `toml::format` receives optional second and
|
||||||
|
third arguments to set them. By default, the witdh is 80 and the precision is
|
||||||
|
`std::numeric_limits<double>::max_digit10`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const auto serial = toml::format(data, /*width = */ 0, /*prec = */ 17);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Underlying types
|
## Underlying types
|
||||||
@@ -618,7 +940,7 @@ The toml types (can be used as `toml::*` in this library) and corresponding `enu
|
|||||||
| LocalDate | `toml::local_date` | `toml::value_t::LocalDate` |
|
| LocalDate | `toml::local_date` | `toml::value_t::LocalDate` |
|
||||||
| LocalTime | `toml::local_time` | `toml::value_t::LocalTime` |
|
| LocalTime | `toml::local_time` | `toml::value_t::LocalTime` |
|
||||||
| LocalDatetime | `toml::local_datetime` | `toml::value_t::LocalDatetime` |
|
| LocalDatetime | `toml::local_datetime` | `toml::value_t::LocalDatetime` |
|
||||||
| OffsetDatetime | `toml::offset_datetime` | `toml::value_t::offsetDatetime` |
|
| OffsetDatetime | `toml::offset_datetime` | `toml::value_t::OffsetDatetime` |
|
||||||
| Array | `std::vector<toml::value>` | `toml::value_t::Array` |
|
| Array | `std::vector<toml::value>` | `toml::value_t::Array` |
|
||||||
| Table | `std::unordered_map<toml::key, toml::value>` | `toml::value_t::Table` |
|
| Table | `std::unordered_map<toml::key, toml::value>` | `toml::value_t::Table` |
|
||||||
|
|
||||||
@@ -633,21 +955,40 @@ 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`.
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
To run test codes, you need to clone toml-lang/toml repository under `build/` directory
|
||||||
|
because some of the test codes read a file in the repository.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ mkdir build
|
||||||
|
$ cd build
|
||||||
|
$ git clone https://github.com/toml-lang/toml.git
|
||||||
|
$ cmake ..
|
||||||
|
$ make
|
||||||
|
$ make test
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the language agnostic test suite, you need to compile
|
||||||
|
`tests/check_toml_test.cpp` and pass it to the tester.
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
I thank the contributor for providing great feature to this repository.
|
I appreciate the help of the contributors who introduced the great feature to this library.
|
||||||
|
|
||||||
- Guillaume Fraux (@Luthaf)
|
- Guillaume Fraux (@Luthaf)
|
||||||
- Windows support and CI on Appvayor
|
- Windows support and CI on Appvayor
|
||||||
- Intel Compiler support
|
- Intel Compiler support
|
||||||
- Quentin Khan (@xaxousis)
|
- Quentin Khan (@xaxousis)
|
||||||
- Found & Fixed a bug around ODR
|
- Found & Fixed a bug around ODR
|
||||||
- Improved error message to show the location where the parser fails
|
- Improved error messages for invaild keys to show the location where the parser fails
|
||||||
|
- Petr Beneš (@wbenny)
|
||||||
|
- Fixed warnings on MSVC
|
||||||
|
|
||||||
## Licensing terms
|
## Licensing terms
|
||||||
|
|
||||||
This product is licensed under the terms of the [MIT License](LICENSE).
|
This product is licensed under the terms of the [MIT License](LICENSE).
|
||||||
|
|
||||||
- Copyright (c) 2017 Toru Niina
|
- Copyright (c) 2017-2019 Toru Niina
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|||||||
@@ -20,15 +20,16 @@ set(TEST_NAMES
|
|||||||
test_parse_inline_table
|
test_parse_inline_table
|
||||||
test_parse_key
|
test_parse_key
|
||||||
test_parse_table_key
|
test_parse_table_key
|
||||||
|
test_literals
|
||||||
test_get
|
test_get
|
||||||
test_get_related_func
|
test_get_related_func
|
||||||
test_to_toml
|
|
||||||
test_from_toml
|
test_from_toml
|
||||||
test_parse_file
|
test_parse_file
|
||||||
test_serialize_file
|
test_serialize_file
|
||||||
test_parse_unicode
|
test_parse_unicode
|
||||||
test_error_detection
|
test_error_detection
|
||||||
test_format_error
|
test_format_error
|
||||||
|
test_extended_conversions
|
||||||
)
|
)
|
||||||
|
|
||||||
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
||||||
@@ -98,3 +99,8 @@ foreach(TEST_NAME ${TEST_NAMES})
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
endforeach(TEST_NAME)
|
endforeach(TEST_NAME)
|
||||||
|
|
||||||
|
# this test is to check it compiles. it will not run
|
||||||
|
add_executable(test_multiple_translation_unit
|
||||||
|
test_multiple_translation_unit_1.cpp
|
||||||
|
test_multiple_translation_unit_2.cpp)
|
||||||
|
|||||||
41
tests/check.cpp
Normal file
41
tests/check.cpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#include "toml.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if(argc != 3)
|
||||||
|
{
|
||||||
|
std::cerr << "usage: ./check [filename] [valid|invalid]" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string file_kind(argv[2]);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto data = toml::parse(argv[1]);
|
||||||
|
std::cout << std::setprecision(16) << std::setw(80) << data;
|
||||||
|
if(file_kind == "valid")
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const toml::syntax_error& err)
|
||||||
|
{
|
||||||
|
std::cout << "what(): " << err.what() << std::endl;
|
||||||
|
if(file_kind == "invalid")
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 127;
|
||||||
|
}
|
||||||
142
tests/check_toml_test.cpp
Normal file
142
tests/check_toml_test.cpp
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#include "toml.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
struct json_serializer
|
||||||
|
{
|
||||||
|
void operator()(toml::boolean v)
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"bool\",\"value\":\"" << toml::value(v) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(toml::integer v)
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"integer\",\"value\":\"" << toml::value(v) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(toml::floating v)
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"float\",\"value\":\"" << toml::value(v) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(const toml::string& v)
|
||||||
|
{
|
||||||
|
// since toml11 automatically convert string to multiline string that is
|
||||||
|
// valid only in TOML, we need to format the string to make it valid in
|
||||||
|
// JSON.
|
||||||
|
std::cout << "{\"type\":\"string\",\"value\":\""
|
||||||
|
<< this->escape_string(v.str) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(const toml::local_time& v)
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"local_time\",\"value\":\"" << toml::value(v) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(const toml::local_date& v)
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"local_date\",\"value\":\"" << toml::value(v) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(const toml::local_datetime& v)
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"local_datetime\",\"value\":\"" << toml::value(v) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(const toml::offset_datetime& v)
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"datetime\",\"value\":\"" << toml::value(v) << "\"}";
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(const toml::array& v)
|
||||||
|
{
|
||||||
|
if(!v.empty() && v.front().is_table())
|
||||||
|
{
|
||||||
|
std::cout << '[';
|
||||||
|
bool is_first = true;
|
||||||
|
for(const auto& elem : v)
|
||||||
|
{
|
||||||
|
if(!is_first) {std::cout << ", ";}
|
||||||
|
is_first = false;
|
||||||
|
toml::visit(*this, elem);
|
||||||
|
}
|
||||||
|
std::cout << ']';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "{\"type\":\"array\",\"value\":[";
|
||||||
|
bool is_first = true;
|
||||||
|
for(const auto& elem : v)
|
||||||
|
{
|
||||||
|
if(!is_first) {std::cout << ", ";}
|
||||||
|
is_first = false;
|
||||||
|
toml::visit(*this, elem);
|
||||||
|
}
|
||||||
|
std::cout << "]}";
|
||||||
|
}
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void operator()(const toml::table& v)
|
||||||
|
{
|
||||||
|
std::cout << '{';
|
||||||
|
bool is_first = true;
|
||||||
|
for(const auto& elem : v)
|
||||||
|
{
|
||||||
|
if(!is_first) {std::cout << ", ";}
|
||||||
|
is_first = false;
|
||||||
|
std::cout << toml::format(toml::string(elem.first),
|
||||||
|
std::numeric_limits<std::size_t>::max());
|
||||||
|
std::cout << ':';
|
||||||
|
toml::visit(*this, elem.second);
|
||||||
|
}
|
||||||
|
std::cout << '}';
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string escape_string(const std::string& s) const
|
||||||
|
{
|
||||||
|
std::string retval;
|
||||||
|
for(const char c : s)
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '\\': {retval += "\\\\"; break;}
|
||||||
|
case '\"': {retval += "\\\""; break;}
|
||||||
|
case '\b': {retval += "\\b"; break;}
|
||||||
|
case '\t': {retval += "\\t"; break;}
|
||||||
|
case '\f': {retval += "\\f"; break;}
|
||||||
|
case '\n': {retval += "\\n"; break;}
|
||||||
|
case '\r': {retval += "\\r"; break;}
|
||||||
|
default : {retval += c; break;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::vector<char> buf;
|
||||||
|
std::cin.peek();
|
||||||
|
while(!std::cin.eof())
|
||||||
|
{
|
||||||
|
buf.push_back(std::cin.get());
|
||||||
|
std::cin.peek();
|
||||||
|
}
|
||||||
|
std::string bufstr(buf.begin(), buf.end());
|
||||||
|
|
||||||
|
std::istringstream ss(bufstr);
|
||||||
|
|
||||||
|
const auto data = toml::parse(ss);
|
||||||
|
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10);
|
||||||
|
toml::visit(json_serializer(), data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch(const toml::syntax_error& err)
|
||||||
|
{
|
||||||
|
std::cout << "what(): " << err.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
116
tests/test_extended_conversions.cpp
Normal file
116
tests/test_extended_conversions.cpp
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#define BOOST_TEST_MODULE "test_extended_conversions"
|
||||||
|
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#else
|
||||||
|
#define BOOST_TEST_NO_LIB
|
||||||
|
#include <boost/test/included/unit_test.hpp>
|
||||||
|
#endif
|
||||||
|
#include <toml.hpp>
|
||||||
|
|
||||||
|
namespace extlib
|
||||||
|
{
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
std::string b;
|
||||||
|
};
|
||||||
|
struct bar
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
std::string b;
|
||||||
|
|
||||||
|
void from_toml(const toml::value& v)
|
||||||
|
{
|
||||||
|
this->a = toml::find<int>(v, "a");
|
||||||
|
this->b = toml::find<std::string>(v, "b");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
toml::table into_toml() const
|
||||||
|
{
|
||||||
|
return toml::table{{"a", this->a}, {"b", this->b}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // extlib
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
struct from<extlib::foo>
|
||||||
|
{
|
||||||
|
static extlib::foo from_toml(const toml::value& v)
|
||||||
|
{
|
||||||
|
return extlib::foo{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct into<extlib::foo>
|
||||||
|
{
|
||||||
|
static toml::table into_toml(const extlib::foo& f)
|
||||||
|
{
|
||||||
|
return toml::table{{"a", f.a}, {"b", f.b}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // toml
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_conversion_by_member_methods)
|
||||||
|
{
|
||||||
|
const toml::value v{{"a", 42}, {"b", "baz"}};
|
||||||
|
|
||||||
|
const auto foo = toml::get<extlib::foo>(v);
|
||||||
|
BOOST_CHECK_EQUAL(foo.a, 42);
|
||||||
|
BOOST_CHECK_EQUAL(foo.b, "baz");
|
||||||
|
|
||||||
|
const toml::value v2(foo);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(v, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_conversion_by_specialization)
|
||||||
|
{
|
||||||
|
const toml::value v{{"a", 42}, {"b", "baz"}};
|
||||||
|
|
||||||
|
const auto bar = toml::get<extlib::bar>(v);
|
||||||
|
BOOST_CHECK_EQUAL(bar.a, 42);
|
||||||
|
BOOST_CHECK_EQUAL(bar.b, "baz");
|
||||||
|
|
||||||
|
const toml::value v2(bar);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(v, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
||||||
|
{
|
||||||
|
const toml::value v{
|
||||||
|
toml::table{{"a", 42}, {"b", "baz"}},
|
||||||
|
toml::table{{"a", 43}, {"b", "qux"}},
|
||||||
|
toml::table{{"a", 44}, {"b", "quux"}},
|
||||||
|
toml::table{{"a", 45}, {"b", "foobar"}},
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto foos = toml::get<std::vector<extlib::foo>>(v);
|
||||||
|
BOOST_CHECK_EQUAL(foos.size() , 4ul);
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(0).a , 42);
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(1).a , 43);
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(2).a , 44);
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(3).a , 45);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(0).b , "baz");
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(1).b , "qux");
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(2).b , "quux");
|
||||||
|
BOOST_CHECK_EQUAL(foos.at(3).b , "foobar");
|
||||||
|
|
||||||
|
const auto bars = toml::get<std::vector<extlib::bar>>(v);
|
||||||
|
BOOST_CHECK_EQUAL(bars.size() , 4ul);
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(0).a , 42);
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(1).a , 43);
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(2).a , 44);
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(3).a , 45);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(0).b , "baz");
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(1).b , "qux");
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(2).b , "quux");
|
||||||
|
BOOST_CHECK_EQUAL(bars.at(3).b , "foobar");
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ BOOST_AUTO_TEST_CASE(test_1_value)
|
|||||||
{
|
{
|
||||||
const std::string pretty_error =
|
const std::string pretty_error =
|
||||||
toml::format_error("[error] test error", val, "this is a value",
|
toml::format_error("[error] test error", val, "this is a value",
|
||||||
std::vector<std::string>{"this is a hint"});
|
{"this is a hint"});
|
||||||
std::cout << pretty_error << std::endl;
|
std::cout << pretty_error << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(test_2_values)
|
|||||||
toml::format_error("[error] test error with two values",
|
toml::format_error("[error] test error with two values",
|
||||||
v1, "this is the answer",
|
v1, "this is the answer",
|
||||||
v2, "this is the pi",
|
v2, "this is the pi",
|
||||||
std::vector<std::string>{"hint"});
|
{"hint"});
|
||||||
std::cout << pretty_error << std::endl;
|
std::cout << pretty_error << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(test_3_values)
|
|||||||
v1, "this is the answer",
|
v1, "this is the answer",
|
||||||
v2, "this is the pi",
|
v2, "this is the pi",
|
||||||
v3, "this is a meta-syntactic variable",
|
v3, "this is a meta-syntactic variable",
|
||||||
std::vector<std::string>{"hint 1", "hint 2"});
|
{"hint 1", "hint 2"});
|
||||||
std::cout << pretty_error << std::endl;
|
std::cout << pretty_error << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,21 +45,194 @@ BOOST_AUTO_TEST_CASE(test_find)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_get_or)
|
BOOST_AUTO_TEST_CASE(test_get_or)
|
||||||
{
|
{
|
||||||
{
|
// requires conversion int -> uint
|
||||||
toml::table v{{"num", 42}};
|
|
||||||
BOOST_CHECK_EQUAL(42, toml::get_or<int>(v, "num", 0));
|
|
||||||
BOOST_CHECK_EQUAL(0, toml::get_or<int>(v, "foo", 0));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
toml::value v = toml::table{{"num", 42}};
|
|
||||||
BOOST_CHECK_EQUAL(42, toml::get_or<int>(v, "num", 0));
|
|
||||||
BOOST_CHECK_EQUAL(0, toml::get_or<int>(v, "foo", 0));
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
toml::value v1(42);
|
toml::value v1(42);
|
||||||
toml::value v2(3.14);
|
toml::value v2(3.14);
|
||||||
BOOST_CHECK_EQUAL(42, toml::get_or<int>(v1, 0));
|
BOOST_CHECK_EQUAL(42u, toml::get_or(v1, 0u));
|
||||||
BOOST_CHECK_EQUAL(0, toml::get_or<int>(v2, 0));
|
BOOST_CHECK_EQUAL(0u, toml::get_or(v2, 0u));
|
||||||
|
}
|
||||||
|
|
||||||
|
// exact toml type
|
||||||
|
{
|
||||||
|
toml::value v1(42);
|
||||||
|
toml::value v2(3.14);
|
||||||
|
|
||||||
|
toml::integer opt(0);
|
||||||
|
BOOST_CHECK_EQUAL(42, toml::get_or(v1, opt));
|
||||||
|
BOOST_CHECK_EQUAL(0, toml::get_or(v2, opt));
|
||||||
|
|
||||||
|
toml::value v3("foobar");
|
||||||
|
toml::string s("bazqux");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::get_or(v3, s));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v1, s));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::string
|
||||||
|
{
|
||||||
|
toml::value v1("foobar");
|
||||||
|
toml::value v2(42);
|
||||||
|
|
||||||
|
std::string s1("bazqux");
|
||||||
|
const std::string s2("bazqux");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s1));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s1));
|
||||||
|
|
||||||
|
std::string& v1r = toml::get_or(v1, s1);
|
||||||
|
std::string& s1r = toml::get_or(v2, s1);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", v1r);
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", s1r);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s2));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s2));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, std::move(s1)));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, std::move(s1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// string literal
|
||||||
|
{
|
||||||
|
toml::value v1("foobar");
|
||||||
|
toml::value v2(42);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, "bazqux"));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, "bazqux"));
|
||||||
|
|
||||||
|
const char* lit = "bazqux";
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, lit));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, lit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_find_or)
|
||||||
|
{
|
||||||
|
// ========================================================================
|
||||||
|
// pass toml::value
|
||||||
|
//
|
||||||
|
// requires conversion int -> uint
|
||||||
|
{
|
||||||
|
toml::table v{{"num", 42}};
|
||||||
|
BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u));
|
||||||
|
BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u));
|
||||||
|
}
|
||||||
|
// exact toml type
|
||||||
|
{
|
||||||
|
toml::table v1{{"key", 42 }};
|
||||||
|
toml::table v2{{"key", 3.14}};
|
||||||
|
toml::table v3{{"not", "key"}};
|
||||||
|
|
||||||
|
toml::integer opt(0);
|
||||||
|
BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", opt));
|
||||||
|
BOOST_CHECK_EQUAL(0, toml::find_or(v2, "key", opt));
|
||||||
|
BOOST_CHECK_EQUAL(0, toml::find_or(v3, "key", opt));
|
||||||
|
|
||||||
|
toml::table v4{{"str", "foobar"}};
|
||||||
|
toml::string s("bazqux");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s));
|
||||||
|
}
|
||||||
|
// std::string
|
||||||
|
{
|
||||||
|
toml::table v1{{"key", "foobar"}};
|
||||||
|
toml::table v2{{"key", 42}};
|
||||||
|
|
||||||
|
std::string s1("bazqux");
|
||||||
|
const std::string s2("bazqux");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1));
|
||||||
|
|
||||||
|
std::string& v1r = toml::find_or(v1, "key", s1);
|
||||||
|
std::string& s1r = toml::find_or(v2, "key", s1);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", v1r);
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", s1r);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1)));
|
||||||
|
s1 = "bazqux"; // restoring moved value
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1)));
|
||||||
|
}
|
||||||
|
// string literal
|
||||||
|
{
|
||||||
|
toml::table v1{{"key", "foobar"}};
|
||||||
|
toml::table v2{{"key",42}};
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux"));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux"));
|
||||||
|
|
||||||
|
const char* lit = "bazqux";
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// pass toml::value
|
||||||
|
//
|
||||||
|
// requires conversion int -> uint
|
||||||
|
{
|
||||||
|
toml::table v = toml::table{{"num", 42}};
|
||||||
|
BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u));
|
||||||
|
BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u));
|
||||||
|
}
|
||||||
|
// exact toml type
|
||||||
|
{
|
||||||
|
toml::value v1 = toml::table{{"key", 42 }};
|
||||||
|
toml::value v2 = toml::table{{"key", 3.14}};
|
||||||
|
toml::value v3 = toml::table{{"not", "key"}};
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", toml::integer(0)));
|
||||||
|
BOOST_CHECK_EQUAL( 0, toml::find_or(v2, "key", toml::integer(0)));
|
||||||
|
BOOST_CHECK_EQUAL( 0, toml::find_or(v3, "key", toml::integer(0)));
|
||||||
|
|
||||||
|
toml::value v4 = toml::table{{"str", "foobar"}};
|
||||||
|
toml::string s("bazqux");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s));
|
||||||
|
}
|
||||||
|
// std::string
|
||||||
|
{
|
||||||
|
toml::value v1 = toml::table{{"key", "foobar"}};
|
||||||
|
toml::value v2 = toml::table{{"key", 42}};
|
||||||
|
|
||||||
|
std::string s1("bazqux");
|
||||||
|
const std::string s2("bazqux");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1));
|
||||||
|
|
||||||
|
std::string& v1r = toml::find_or(v1, "key", s1);
|
||||||
|
std::string& s1r = toml::find_or(v2, "key", s1);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", v1r);
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", s1r);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1)));
|
||||||
|
s1 = "bazqux"; // restoring moved value
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1)));
|
||||||
|
}
|
||||||
|
// string literal
|
||||||
|
{
|
||||||
|
toml::value v1 = toml::table{{"key", "foobar"}};
|
||||||
|
toml::value v2 = toml::table{{"key",42}};
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux"));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux"));
|
||||||
|
|
||||||
|
const char* lit = "bazqux";
|
||||||
|
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit));
|
||||||
|
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
154
tests/test_literals.cpp
Normal file
154
tests/test_literals.cpp
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#define BOOST_TEST_MODULE "test_literals"
|
||||||
|
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#else
|
||||||
|
#define BOOST_TEST_NO_LIB
|
||||||
|
#include <boost/test/included/unit_test.hpp>
|
||||||
|
#endif
|
||||||
|
#include <toml.hpp>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_file_as_literal)
|
||||||
|
{
|
||||||
|
using namespace toml::literals::toml_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
const toml::value r{{"a", 42}, {"b", "baz"}};
|
||||||
|
const toml::value v = u8R"(
|
||||||
|
a = 42
|
||||||
|
b = "baz"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(r, v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value r{
|
||||||
|
{"c", 3.14},
|
||||||
|
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
|
||||||
|
};
|
||||||
|
const toml::value v = u8R"(
|
||||||
|
c = 3.14
|
||||||
|
[table]
|
||||||
|
a = 42
|
||||||
|
b = "baz"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(r, v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value r{
|
||||||
|
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
|
||||||
|
};
|
||||||
|
const toml::value v = u8R"(
|
||||||
|
[table]
|
||||||
|
a = 42
|
||||||
|
b = "baz"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(r, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
||||||
|
{
|
||||||
|
using namespace toml::literals::toml_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8"true"_toml;
|
||||||
|
const toml::value v2 = u8"false"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
|
BOOST_CHECK(v2.is_boolean());
|
||||||
|
BOOST_CHECK(toml::get<bool>(v1));
|
||||||
|
BOOST_CHECK(!toml::get<bool>(v2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8"123_456"_toml;
|
||||||
|
const toml::value v2 = u8"0b0010"_toml;
|
||||||
|
const toml::value v3 = u8"0xDEADBEEF"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_integer());
|
||||||
|
BOOST_CHECK(v2.is_integer());
|
||||||
|
BOOST_CHECK(v3.is_integer());
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v1), 123456);
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v2), 2);
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v3), 0xDEADBEEF);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8"3.1415"_toml;
|
||||||
|
const toml::value v2 = u8"6.02e+23"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_float());
|
||||||
|
BOOST_CHECK(v2.is_float());
|
||||||
|
BOOST_CHECK_CLOSE(toml::get<double>(v1), 3.1415, 0.00001);
|
||||||
|
BOOST_CHECK_CLOSE(toml::get<double>(v2), 6.02e23, 0.0001);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8R"("foo")"_toml;
|
||||||
|
const toml::value v2 = u8R"('foo')"_toml;
|
||||||
|
const toml::value v3 = u8R"("""foo""")"_toml;
|
||||||
|
const toml::value v4 = u8R"('''foo''')"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_string());
|
||||||
|
BOOST_CHECK(v2.is_string());
|
||||||
|
BOOST_CHECK(v3.is_string());
|
||||||
|
BOOST_CHECK(v4.is_string());
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<std::string>(v1), "foo");
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<std::string>(v2), "foo");
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<std::string>(v3), "foo");
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<std::string>(v4), "foo");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8R"([1,2,3])"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_array());
|
||||||
|
BOOST_CHECK((toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3}));
|
||||||
|
|
||||||
|
const toml::value v2 = u8R"([1,])"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v2.is_array());
|
||||||
|
BOOST_CHECK((toml::get<std::vector<int>>(v2) == std::vector<int>{1}));
|
||||||
|
|
||||||
|
const toml::value v3 = u8R"([[1,]])"_toml;
|
||||||
|
BOOST_CHECK(v3.is_array());
|
||||||
|
BOOST_CHECK((toml::get<std::vector<int>>(toml::get<toml::array>(v3).front()) == std::vector<int>{1}));
|
||||||
|
|
||||||
|
const toml::value v4 = u8R"([[1],])"_toml;
|
||||||
|
BOOST_CHECK(v4.is_array());
|
||||||
|
BOOST_CHECK((toml::get<std::vector<int>>(toml::get<toml::array>(v4).front()) == std::vector<int>{1}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8R"({a = 42})"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_table());
|
||||||
|
BOOST_CHECK((toml::get<std::map<std::string,int>>(v1) ==
|
||||||
|
std::map<std::string,int>{{"a", 42}}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8"1979-05-27"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_local_date());
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<toml::local_date>(v1),
|
||||||
|
toml::local_date(1979, toml::month_t::May, 27));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8"12:00:00"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK(v1.is_local_time());
|
||||||
|
BOOST_CHECK(toml::get<std::chrono::hours>(v1) == std::chrono::hours(12));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = u8"1979-05-27T07:32:00"_toml;
|
||||||
|
BOOST_CHECK(v1.is_local_datetime());
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<toml::local_datetime>(v1),
|
||||||
|
toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||||
|
toml::local_time(7, 32, 0)));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = "1979-05-27T07:32:00Z"_toml;
|
||||||
|
BOOST_CHECK(v1.is_offset_datetime());
|
||||||
|
BOOST_CHECK_EQUAL(toml::get<toml::offset_datetime>(v1),
|
||||||
|
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||||
|
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
11
tests/test_multiple_translation_unit_1.cpp
Normal file
11
tests/test_multiple_translation_unit_1.cpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <toml.hpp>
|
||||||
|
|
||||||
|
int read_a(const toml::table&);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const std::string content("a = 0");
|
||||||
|
std::istringstream iss(content);
|
||||||
|
const auto data = toml::parse(iss, "test_multiple_translation_unit.toml");
|
||||||
|
return read_a(data);
|
||||||
|
}
|
||||||
6
tests/test_multiple_translation_unit_2.cpp
Normal file
6
tests/test_multiple_translation_unit_2.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <toml.hpp>
|
||||||
|
|
||||||
|
int read_a(const toml::table& t)
|
||||||
|
{
|
||||||
|
return toml::get<int>(t.at("a"));
|
||||||
|
}
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
#define BOOST_TEST_MODULE "test_to_toml"
|
|
||||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#else
|
|
||||||
#define BOOST_TEST_NO_LIB
|
|
||||||
#include <boost/test/included/unit_test.hpp>
|
|
||||||
#endif
|
|
||||||
#include <toml.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_boolean)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(true);
|
|
||||||
toml::value v2 = toml::to_toml(false);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
|
||||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
|
||||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_integer)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(-42);
|
|
||||||
toml::value v2 = toml::to_toml(42u);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Integer);
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Integer);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Integer));
|
|
||||||
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
|
||||||
BOOST_CHECK(v1.is<toml::Integer>());
|
|
||||||
BOOST_CHECK(v2.is<toml::Integer>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_float)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(3.14);
|
|
||||||
toml::value v2 = toml::to_toml(3.14f);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Float);
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Float));
|
|
||||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
|
||||||
BOOST_CHECK(v1.is<toml::Float>());
|
|
||||||
BOOST_CHECK(v2.is<toml::Float>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Float>(), 3.14);
|
|
||||||
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_string)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(std::string("foo"));
|
|
||||||
toml::value v2 = toml::to_toml(std::string("foo"), toml::string_t::literal);
|
|
||||||
toml::value v3 = toml::to_toml("foo");
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::String);
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::String);
|
|
||||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::String);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::String));
|
|
||||||
BOOST_CHECK(v2.is(toml::value_t::String));
|
|
||||||
BOOST_CHECK(v3.is(toml::value_t::String));
|
|
||||||
BOOST_CHECK(v1.is<toml::String>());
|
|
||||||
BOOST_CHECK(v2.is<toml::String>());
|
|
||||||
BOOST_CHECK(v3.is<toml::String>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "foo");
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "foo");
|
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::String>(), "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_local_date)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(toml::local_date(2018, toml::month_t::Jan, 31));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
|
||||||
BOOST_CHECK(v1.is<toml::LocalDate>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
|
||||||
toml::local_date(2018, toml::month_t::Jan, 31));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_local_time)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(toml::local_time(12, 30, 45));
|
|
||||||
toml::value v2 = toml::to_toml(std::chrono::hours(12) + std::chrono::minutes(30) +
|
|
||||||
std::chrono::seconds(45));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime);
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalTime);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalTime));
|
|
||||||
BOOST_CHECK(v2.is(toml::value_t::LocalTime));
|
|
||||||
BOOST_CHECK(v1.is<toml::LocalTime>());
|
|
||||||
BOOST_CHECK(v2.is<toml::LocalTime>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
|
||||||
toml::local_time(12, 30, 45));
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalTime>(),
|
|
||||||
toml::local_time(12, 30, 45));
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
|
||||||
v2.cast<toml::value_t::LocalTime>());
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(toml::local_datetime(
|
|
||||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
|
||||||
toml::local_time(12, 30, 45)
|
|
||||||
));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
|
||||||
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
|
||||||
toml::local_datetime(
|
|
||||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
|
||||||
toml::local_time(12, 30, 45)));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml(toml::offset_datetime(
|
|
||||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
|
||||||
toml::local_time(12, 30, 45),
|
|
||||||
toml::time_offset(9, 0)
|
|
||||||
));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
|
||||||
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
|
||||||
toml::offset_datetime(
|
|
||||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
|
||||||
toml::local_time(12, 30, 45),
|
|
||||||
toml::time_offset(9, 0)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_array)
|
|
||||||
{
|
|
||||||
std::vector<int> v{1,2,3,4,5};
|
|
||||||
toml::value v1 = toml::to_toml(v);
|
|
||||||
toml::value v2 = toml::to_toml(6,7,8,9,0);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Array));
|
|
||||||
BOOST_CHECK(v1.is<toml::Array>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
|
||||||
BOOST_CHECK(v2.is(toml::value_t::Array));
|
|
||||||
BOOST_CHECK(v2.is<toml::Array>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 3);
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 4);
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 5);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 8);
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 9);
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_table)
|
|
||||||
{
|
|
||||||
toml::value v1 = toml::to_toml({{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}});
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Table));
|
|
||||||
BOOST_CHECK(v1.is<toml::Table>());
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Integer>(), 42);
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "qux");
|
|
||||||
}
|
|
||||||
@@ -20,6 +20,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
|
BOOST_CHECK(v2.is_boolean());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||||
@@ -33,6 +35,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
|
BOOST_CHECK(v2.is_boolean());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), false);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), false);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
||||||
@@ -48,6 +52,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
|||||||
BOOST_CHECK(v4.is(toml::value_t::Boolean));
|
BOOST_CHECK(v4.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v3.is<toml::Boolean>());
|
BOOST_CHECK(v3.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v4.is<toml::Boolean>());
|
BOOST_CHECK(v4.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v3.is_boolean());
|
||||||
|
BOOST_CHECK(v4.is_boolean());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Boolean>(), false);
|
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Boolean>(), false);
|
||||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Boolean>(), true);
|
||||||
@@ -61,6 +67,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
|||||||
BOOST_CHECK(v6.is(toml::value_t::Boolean));
|
BOOST_CHECK(v6.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v5.is<toml::Boolean>());
|
BOOST_CHECK(v5.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v6.is<toml::Boolean>());
|
BOOST_CHECK(v6.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v3.is_boolean());
|
||||||
|
BOOST_CHECK(v4.is_boolean());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Boolean>(), false);
|
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Boolean>(), false);
|
||||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Boolean>(), true);
|
||||||
@@ -74,6 +82,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||||
BOOST_CHECK(v1.is<toml::Integer>());
|
BOOST_CHECK(v1.is<toml::Integer>());
|
||||||
BOOST_CHECK(v2.is<toml::Float>());
|
BOOST_CHECK(v2.is<toml::Float>());
|
||||||
|
BOOST_CHECK(v1.is_integer());
|
||||||
|
BOOST_CHECK(v2.is_float());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 42);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 42);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 3.14);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 3.14);
|
||||||
@@ -90,6 +100,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
||||||
BOOST_CHECK(v1.is<toml::Integer>());
|
BOOST_CHECK(v1.is<toml::Integer>());
|
||||||
BOOST_CHECK(v2.is<toml::Integer>());
|
BOOST_CHECK(v2.is<toml::Integer>());
|
||||||
|
BOOST_CHECK(v1.is_integer());
|
||||||
|
BOOST_CHECK(v2.is_integer());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
|
||||||
@@ -103,6 +115,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
||||||
BOOST_CHECK(v1.is<toml::Integer>());
|
BOOST_CHECK(v1.is<toml::Integer>());
|
||||||
BOOST_CHECK(v2.is<toml::Integer>());
|
BOOST_CHECK(v2.is<toml::Integer>());
|
||||||
|
BOOST_CHECK(v1.is_integer());
|
||||||
|
BOOST_CHECK(v2.is_integer());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 54);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 54);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), -54);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), -54);
|
||||||
@@ -118,6 +132,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
|||||||
BOOST_CHECK(v4.is(toml::value_t::Integer));
|
BOOST_CHECK(v4.is(toml::value_t::Integer));
|
||||||
BOOST_CHECK(v3.is<toml::Integer>());
|
BOOST_CHECK(v3.is<toml::Integer>());
|
||||||
BOOST_CHECK(v4.is<toml::Integer>());
|
BOOST_CHECK(v4.is<toml::Integer>());
|
||||||
|
BOOST_CHECK(v3.is_integer());
|
||||||
|
BOOST_CHECK(v4.is_integer());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Integer>(), 54);
|
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Integer>(), 54);
|
||||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Integer>(), -54);
|
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Integer>(), -54);
|
||||||
@@ -131,6 +147,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
|||||||
BOOST_CHECK(v6.is(toml::value_t::Integer));
|
BOOST_CHECK(v6.is(toml::value_t::Integer));
|
||||||
BOOST_CHECK(v5.is<toml::Integer>());
|
BOOST_CHECK(v5.is<toml::Integer>());
|
||||||
BOOST_CHECK(v6.is<toml::Integer>());
|
BOOST_CHECK(v6.is<toml::Integer>());
|
||||||
|
BOOST_CHECK(v5.is_integer());
|
||||||
|
BOOST_CHECK(v6.is_integer());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Integer>(), 54);
|
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Integer>(), 54);
|
||||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Integer>(), -54);
|
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Integer>(), -54);
|
||||||
@@ -144,6 +162,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
|
BOOST_CHECK(v2.is_boolean());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||||
@@ -160,6 +180,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||||
BOOST_CHECK(v1.is<toml::Float>());
|
BOOST_CHECK(v1.is<toml::Float>());
|
||||||
BOOST_CHECK(v2.is<toml::Float>());
|
BOOST_CHECK(v2.is<toml::Float>());
|
||||||
|
BOOST_CHECK(v1.is_float());
|
||||||
|
BOOST_CHECK(v2.is_float());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Float>(), 3.14);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Float>(), 3.14);
|
||||||
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
|
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
|
||||||
@@ -173,6 +195,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||||
BOOST_CHECK(v1.is<toml::Float>());
|
BOOST_CHECK(v1.is<toml::Float>());
|
||||||
BOOST_CHECK(v2.is<toml::Float>());
|
BOOST_CHECK(v2.is<toml::Float>());
|
||||||
|
BOOST_CHECK(v1.is_float());
|
||||||
|
BOOST_CHECK(v2.is_float());
|
||||||
|
|
||||||
BOOST_CHECK_CLOSE_FRACTION(v1.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
BOOST_CHECK_CLOSE_FRACTION(v1.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 2.718);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 2.718);
|
||||||
@@ -188,6 +212,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
|||||||
BOOST_CHECK(v4.is(toml::value_t::Float));
|
BOOST_CHECK(v4.is(toml::value_t::Float));
|
||||||
BOOST_CHECK(v3.is<toml::Float>());
|
BOOST_CHECK(v3.is<toml::Float>());
|
||||||
BOOST_CHECK(v4.is<toml::Float>());
|
BOOST_CHECK(v4.is<toml::Float>());
|
||||||
|
BOOST_CHECK(v3.is_float());
|
||||||
|
BOOST_CHECK(v4.is_float());
|
||||||
|
|
||||||
BOOST_CHECK_CLOSE_FRACTION(v3.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
BOOST_CHECK_CLOSE_FRACTION(v3.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
||||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Float>(), 2.718);
|
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Float>(), 2.718);
|
||||||
@@ -201,6 +227,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
|||||||
BOOST_CHECK(v6.is(toml::value_t::Float));
|
BOOST_CHECK(v6.is(toml::value_t::Float));
|
||||||
BOOST_CHECK(v5.is<toml::Float>());
|
BOOST_CHECK(v5.is<toml::Float>());
|
||||||
BOOST_CHECK(v6.is<toml::Float>());
|
BOOST_CHECK(v6.is<toml::Float>());
|
||||||
|
BOOST_CHECK(v5.is_float());
|
||||||
|
BOOST_CHECK(v6.is_float());
|
||||||
|
|
||||||
BOOST_CHECK_CLOSE_FRACTION(v5.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
BOOST_CHECK_CLOSE_FRACTION(v5.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
||||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Float>(), 2.718);
|
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Float>(), 2.718);
|
||||||
@@ -214,6 +242,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
|
BOOST_CHECK(v2.is_boolean());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||||
@@ -234,6 +264,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
|||||||
BOOST_CHECK(v1.is<toml::String>());
|
BOOST_CHECK(v1.is<toml::String>());
|
||||||
BOOST_CHECK(v2.is<toml::String>());
|
BOOST_CHECK(v2.is<toml::String>());
|
||||||
BOOST_CHECK(v3.is<toml::String>());
|
BOOST_CHECK(v3.is<toml::String>());
|
||||||
|
BOOST_CHECK(v1.is_string());
|
||||||
|
BOOST_CHECK(v2.is_string());
|
||||||
|
BOOST_CHECK(v3.is_string());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "foo");
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "foo");
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "foo");
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "foo");
|
||||||
@@ -249,9 +282,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
|||||||
BOOST_CHECK(v1.is(toml::value_t::String));
|
BOOST_CHECK(v1.is(toml::value_t::String));
|
||||||
BOOST_CHECK(v2.is(toml::value_t::String));
|
BOOST_CHECK(v2.is(toml::value_t::String));
|
||||||
BOOST_CHECK(v3.is(toml::value_t::String));
|
BOOST_CHECK(v3.is(toml::value_t::String));
|
||||||
BOOST_CHECK(v1.is<toml::String>());
|
BOOST_CHECK(v1.is_string());
|
||||||
BOOST_CHECK(v2.is<toml::String>());
|
BOOST_CHECK(v2.is_string());
|
||||||
BOOST_CHECK(v3.is<toml::String>());
|
BOOST_CHECK(v3.is_string());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "bar");
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "bar");
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "bar");
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "bar");
|
||||||
@@ -273,6 +306,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
|||||||
BOOST_CHECK(v4.is<toml::String>());
|
BOOST_CHECK(v4.is<toml::String>());
|
||||||
BOOST_CHECK(v5.is<toml::String>());
|
BOOST_CHECK(v5.is<toml::String>());
|
||||||
BOOST_CHECK(v6.is<toml::String>());
|
BOOST_CHECK(v6.is<toml::String>());
|
||||||
|
BOOST_CHECK(v4.is_string());
|
||||||
|
BOOST_CHECK(v5.is_string());
|
||||||
|
BOOST_CHECK(v6.is_string());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "bar");
|
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "bar");
|
||||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "bar");
|
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "bar");
|
||||||
@@ -291,6 +327,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
|||||||
BOOST_CHECK(v4.is<toml::String>());
|
BOOST_CHECK(v4.is<toml::String>());
|
||||||
BOOST_CHECK(v5.is<toml::String>());
|
BOOST_CHECK(v5.is<toml::String>());
|
||||||
BOOST_CHECK(v6.is<toml::String>());
|
BOOST_CHECK(v6.is<toml::String>());
|
||||||
|
BOOST_CHECK(v4.is_string());
|
||||||
|
BOOST_CHECK(v5.is_string());
|
||||||
|
BOOST_CHECK(v6.is_string());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "baz");
|
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "baz");
|
||||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "baz");
|
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "baz");
|
||||||
@@ -309,6 +348,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
|||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||||
BOOST_CHECK(v3.is<toml::Boolean>());
|
BOOST_CHECK(v3.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
|
BOOST_CHECK(v2.is_boolean());
|
||||||
|
BOOST_CHECK(v3.is_boolean());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
||||||
@@ -322,6 +364,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
||||||
BOOST_CHECK(v1.is<toml::LocalDate>());
|
BOOST_CHECK(v1.is<toml::LocalDate>());
|
||||||
|
BOOST_CHECK(v1.is_local_date());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
||||||
toml::local_date(2018, toml::month_t::Jan, 31));
|
toml::local_date(2018, toml::month_t::Jan, 31));
|
||||||
@@ -331,6 +374,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
||||||
BOOST_CHECK(v1.is<toml::LocalDate>());
|
BOOST_CHECK(v1.is<toml::LocalDate>());
|
||||||
|
BOOST_CHECK(v1.is_local_date());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
||||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||||
@@ -341,6 +385,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
|||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDate);
|
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDate);
|
||||||
BOOST_CHECK(v2.is(toml::value_t::LocalDate));
|
BOOST_CHECK(v2.is(toml::value_t::LocalDate));
|
||||||
BOOST_CHECK(v2.is<toml::LocalDate>());
|
BOOST_CHECK(v2.is<toml::LocalDate>());
|
||||||
|
BOOST_CHECK(v2.is_local_date());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDate>(),
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDate>(),
|
||||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||||
@@ -349,6 +394,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,6 +410,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
|||||||
BOOST_CHECK(v2.is(toml::value_t::LocalTime));
|
BOOST_CHECK(v2.is(toml::value_t::LocalTime));
|
||||||
BOOST_CHECK(v1.is<toml::LocalTime>());
|
BOOST_CHECK(v1.is<toml::LocalTime>());
|
||||||
BOOST_CHECK(v2.is<toml::LocalTime>());
|
BOOST_CHECK(v2.is<toml::LocalTime>());
|
||||||
|
BOOST_CHECK(v1.is_local_time());
|
||||||
|
BOOST_CHECK(v2.is_local_time());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||||
toml::local_time(12, 30, 45));
|
toml::local_time(12, 30, 45));
|
||||||
@@ -377,6 +425,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalTime));
|
BOOST_CHECK(v1.is(toml::value_t::LocalTime));
|
||||||
BOOST_CHECK(v1.is<toml::LocalTime>());
|
BOOST_CHECK(v1.is<toml::LocalTime>());
|
||||||
|
BOOST_CHECK(v1.is_local_time());
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||||
toml::local_time(1, 30, 0, 100, 0));
|
toml::local_time(1, 30, 0, 100, 0));
|
||||||
|
|
||||||
@@ -386,6 +435,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
|||||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::LocalTime);
|
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::LocalTime);
|
||||||
BOOST_CHECK(v3.is(toml::value_t::LocalTime));
|
BOOST_CHECK(v3.is(toml::value_t::LocalTime));
|
||||||
BOOST_CHECK(v3.is<toml::LocalTime>());
|
BOOST_CHECK(v3.is<toml::LocalTime>());
|
||||||
|
BOOST_CHECK(v3.is_local_time());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::LocalTime>(),
|
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::LocalTime>(),
|
||||||
toml::local_time(1, 30, 0, 100, 0));
|
toml::local_time(1, 30, 0, 100, 0));
|
||||||
@@ -394,6 +444,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,6 +458,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
||||||
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
||||||
|
BOOST_CHECK(v1.is_local_datetime());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
||||||
toml::local_datetime(
|
toml::local_datetime(
|
||||||
@@ -420,6 +472,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
||||||
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
||||||
|
BOOST_CHECK(v1.is_local_datetime());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
||||||
toml::local_datetime(
|
toml::local_datetime(
|
||||||
@@ -432,6 +485,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDatetime);
|
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDatetime);
|
||||||
BOOST_CHECK(v2.is(toml::value_t::LocalDatetime));
|
BOOST_CHECK(v2.is(toml::value_t::LocalDatetime));
|
||||||
BOOST_CHECK(v2.is<toml::LocalDatetime>());
|
BOOST_CHECK(v2.is<toml::LocalDatetime>());
|
||||||
|
BOOST_CHECK(v2.is_local_datetime());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDatetime>(),
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDatetime>(),
|
||||||
toml::local_datetime(
|
toml::local_datetime(
|
||||||
@@ -442,6 +496,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,6 +511,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
||||||
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
||||||
|
BOOST_CHECK(v1.is_offset_datetime());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
||||||
toml::offset_datetime(
|
toml::offset_datetime(
|
||||||
@@ -472,6 +528,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
||||||
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
||||||
|
BOOST_CHECK(v1.is_offset_datetime());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
||||||
toml::offset_datetime(
|
toml::offset_datetime(
|
||||||
@@ -485,6 +542,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::OffsetDatetime);
|
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::OffsetDatetime);
|
||||||
BOOST_CHECK(v2.is(toml::value_t::OffsetDatetime));
|
BOOST_CHECK(v2.is(toml::value_t::OffsetDatetime));
|
||||||
BOOST_CHECK(v2.is<toml::OffsetDatetime>());
|
BOOST_CHECK(v2.is<toml::OffsetDatetime>());
|
||||||
|
BOOST_CHECK(v2.is_offset_datetime());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::OffsetDatetime>(),
|
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::OffsetDatetime>(),
|
||||||
toml::offset_datetime(
|
toml::offset_datetime(
|
||||||
@@ -495,6 +553,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,10 +566,12 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Array));
|
BOOST_CHECK(v1.is(toml::value_t::Array));
|
||||||
BOOST_CHECK(v1.is<toml::Array>());
|
BOOST_CHECK(v1.is<toml::Array>());
|
||||||
|
BOOST_CHECK(v1.is_array());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
||||||
BOOST_CHECK(v2.is(toml::value_t::Array));
|
BOOST_CHECK(v2.is(toml::value_t::Array));
|
||||||
BOOST_CHECK(v2.is<toml::Array>());
|
BOOST_CHECK(v2.is<toml::Array>());
|
||||||
|
BOOST_CHECK(v2.is_array());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
|
||||||
@@ -530,10 +591,12 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Array));
|
BOOST_CHECK(v1.is(toml::value_t::Array));
|
||||||
BOOST_CHECK(v1.is<toml::Array>());
|
BOOST_CHECK(v1.is<toml::Array>());
|
||||||
|
BOOST_CHECK(v1.is_array());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
||||||
BOOST_CHECK(v2.is(toml::value_t::Array));
|
BOOST_CHECK(v2.is(toml::value_t::Array));
|
||||||
BOOST_CHECK(v2.is<toml::Array>());
|
BOOST_CHECK(v2.is<toml::Array>());
|
||||||
|
BOOST_CHECK(v2.is_array());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
||||||
@@ -553,6 +616,7 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
|||||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Array);
|
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Array);
|
||||||
BOOST_CHECK(v3.is(toml::value_t::Array));
|
BOOST_CHECK(v3.is(toml::value_t::Array));
|
||||||
BOOST_CHECK(v3.is<toml::Array>());
|
BOOST_CHECK(v3.is<toml::Array>());
|
||||||
|
BOOST_CHECK(v3.is_array());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
||||||
@@ -564,6 +628,7 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,6 +639,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Table));
|
BOOST_CHECK(v1.is(toml::value_t::Table));
|
||||||
BOOST_CHECK(v1.is<toml::Table>());
|
BOOST_CHECK(v1.is<toml::Table>());
|
||||||
|
BOOST_CHECK(v1.is_table());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Integer>(), 42);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Integer>(), 42);
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
|
||||||
@@ -584,6 +650,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Table));
|
BOOST_CHECK(v1.is(toml::value_t::Table));
|
||||||
BOOST_CHECK(v1.is<toml::Table>());
|
BOOST_CHECK(v1.is<toml::Table>());
|
||||||
|
BOOST_CHECK(v1.is_table());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
|
||||||
@@ -595,6 +662,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
|||||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Table);
|
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Table);
|
||||||
BOOST_CHECK(v3.is(toml::value_t::Table));
|
BOOST_CHECK(v3.is(toml::value_t::Table));
|
||||||
BOOST_CHECK(v3.is<toml::Table>());
|
BOOST_CHECK(v3.is<toml::Table>());
|
||||||
|
BOOST_CHECK(v3.is_table());
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
|
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
|
||||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
|
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
|
||||||
@@ -604,5 +672,13 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
|||||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||||
|
BOOST_CHECK(v1.is_boolean());
|
||||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_value_empty)
|
||||||
|
{
|
||||||
|
toml::value v1;
|
||||||
|
BOOST_CHECK(v1.is_uninitialized());
|
||||||
|
BOOST_CHECK(v1.is(toml::value_t::Empty));
|
||||||
|
}
|
||||||
|
|||||||
2
toml.hpp
2
toml.hpp
@@ -34,8 +34,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "toml/parser.hpp"
|
#include "toml/parser.hpp"
|
||||||
|
#include "toml/literal.hpp"
|
||||||
#include "toml/serializer.hpp"
|
#include "toml/serializer.hpp"
|
||||||
#include "toml/to_toml.hpp"
|
|
||||||
#include "toml/from_toml.hpp"
|
#include "toml/from_toml.hpp"
|
||||||
#include "toml/get.hpp"
|
#include "toml/get.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,10 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <array>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
// they scans characters and returns region if it matches to the condition.
|
// they scans characters and returns region if it matches to the condition.
|
||||||
@@ -38,10 +41,12 @@ inline std::string show_char(const char c)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::array<char, 5> buf;
|
||||||
oss << "0x" << std::hex << std::setfill('0') << std::setw(2)
|
buf.fill('\0');
|
||||||
<< static_cast<int>(c);
|
const auto r = std::snprintf(
|
||||||
return oss.str();
|
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
|
||||||
|
assert(r == buf.size() - 1);
|
||||||
|
return std::string(buf.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +56,8 @@ struct character
|
|||||||
static constexpr char target = C;
|
static constexpr char target = C;
|
||||||
|
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
@@ -62,10 +68,14 @@ struct character
|
|||||||
const char c = *(loc.iter());
|
const char c = *(loc.iter());
|
||||||
if(c != target)
|
if(c != target)
|
||||||
{
|
{
|
||||||
return err(concat_to_string("expected '", show_char(target),
|
if(msg)
|
||||||
"' but got '", show_char(c), "'."));
|
{
|
||||||
|
return err(concat_to_string("expected '", show_char(target),
|
||||||
|
"' but got '", show_char(c), "'."));
|
||||||
|
}
|
||||||
|
return err("");
|
||||||
}
|
}
|
||||||
++(loc.iter()); // update location
|
loc.advance(); // update location
|
||||||
|
|
||||||
return ok(region<Cont>(loc, first, loc.iter()));
|
return ok(region<Cont>(loc, first, loc.iter()));
|
||||||
}
|
}
|
||||||
@@ -86,7 +96,8 @@ struct in_range
|
|||||||
static constexpr char lower = Low;
|
static constexpr char lower = Low;
|
||||||
|
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
@@ -97,12 +108,16 @@ struct in_range
|
|||||||
const char c = *(loc.iter());
|
const char c = *(loc.iter());
|
||||||
if(c < lower || upper < c)
|
if(c < lower || upper < c)
|
||||||
{
|
{
|
||||||
return err(concat_to_string("expected character in range "
|
if(msg)
|
||||||
"[", show_char(lower), ", ", show_char(upper), "] but got ",
|
{
|
||||||
"'", show_char(c), "'."));
|
return err(concat_to_string("expected character in range "
|
||||||
|
"[", show_char(lower), ", ", show_char(upper), "] but got ",
|
||||||
|
"'", show_char(c), "'."));
|
||||||
|
}
|
||||||
|
return err("");
|
||||||
}
|
}
|
||||||
|
|
||||||
++(loc.iter());
|
loc.advance();
|
||||||
return ok(region<Cont>(loc, first, loc.iter()));
|
return ok(region<Cont>(loc, first, loc.iter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +135,8 @@ template<typename Combinator>
|
|||||||
struct exclude
|
struct exclude
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
@@ -128,15 +144,18 @@ struct exclude
|
|||||||
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
||||||
auto first = loc.iter();
|
auto first = loc.iter();
|
||||||
|
|
||||||
auto rslt = Combinator::invoke(loc);
|
auto rslt = Combinator::invoke(loc, msg);
|
||||||
if(rslt.is_ok())
|
if(rslt.is_ok())
|
||||||
{
|
{
|
||||||
loc.iter() = first; // rollback
|
loc.reset(first);
|
||||||
return err(concat_to_string(
|
if(msg)
|
||||||
"invalid pattern (", Combinator::pattern(), ") appeared ",
|
{
|
||||||
rslt.unwrap().str()));
|
return err(concat_to_string("invalid pattern (",
|
||||||
|
Combinator::pattern(), ") appeared ", rslt.unwrap().str()));
|
||||||
|
}
|
||||||
|
return err("");
|
||||||
}
|
}
|
||||||
loc.iter() = std::next(first);
|
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
|
||||||
return ok(region<Cont>(loc, first, loc.iter()));
|
return ok(region<Cont>(loc, first, loc.iter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,12 +170,13 @@ template<typename Combinator>
|
|||||||
struct maybe
|
struct maybe
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
const auto rslt = Combinator::invoke(loc);
|
const auto rslt = Combinator::invoke(loc, msg);
|
||||||
if(rslt.is_ok())
|
if(rslt.is_ok())
|
||||||
{
|
{
|
||||||
return rslt;
|
return rslt;
|
||||||
@@ -177,34 +197,36 @@ template<typename Head, typename ... Tail>
|
|||||||
struct sequence<Head, Tail...>
|
struct sequence<Head, Tail...>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc, msg);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(rslt.unwrap_err());
|
return err(rslt.unwrap_err());
|
||||||
}
|
}
|
||||||
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
|
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from the above function only, recursively.
|
// called from the above function only, recursively.
|
||||||
template<typename Cont, typename Iterator>
|
template<typename Cont, typename Iterator>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, std::string>
|
||||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
invoke(location<Cont>& loc, region<Cont> reg, Iterator first,
|
||||||
|
const bool msg = false)
|
||||||
{
|
{
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc, msg);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(rslt.unwrap_err());
|
return err(rslt.unwrap_err());
|
||||||
}
|
}
|
||||||
reg += rslt.unwrap(); // concat regions
|
reg += rslt.unwrap(); // concat regions
|
||||||
return sequence<Tail...>::invoke(loc, std::move(reg), first);
|
return sequence<Tail...>::invoke(loc, std::move(reg), first, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string pattern()
|
static std::string pattern()
|
||||||
@@ -219,12 +241,13 @@ struct sequence<Head>
|
|||||||
// would be called from sequence<T ...>::invoke only.
|
// would be called from sequence<T ...>::invoke only.
|
||||||
template<typename Cont, typename Iterator>
|
template<typename Cont, typename Iterator>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, std::string>
|
||||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
invoke(location<Cont>& loc, region<Cont> reg, Iterator first,
|
||||||
|
const bool msg = false)
|
||||||
{
|
{
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc, msg);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(rslt.unwrap_err());
|
return err(rslt.unwrap_err());
|
||||||
}
|
}
|
||||||
reg += rslt.unwrap(); // concat regions
|
reg += rslt.unwrap(); // concat regions
|
||||||
@@ -240,14 +263,15 @@ template<typename Head, typename ... Tail>
|
|||||||
struct either<Head, Tail...>
|
struct either<Head, Tail...>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc, msg);
|
||||||
if(rslt.is_ok()) {return rslt;}
|
if(rslt.is_ok()) {return rslt;}
|
||||||
return either<Tail...>::invoke(loc);
|
return either<Tail...>::invoke(loc, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string pattern()
|
static std::string pattern()
|
||||||
@@ -259,11 +283,12 @@ template<typename Head>
|
|||||||
struct either<Head>
|
struct either<Head>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
return Head::invoke(loc);
|
return Head::invoke(loc, msg);
|
||||||
}
|
}
|
||||||
static std::string pattern()
|
static std::string pattern()
|
||||||
{
|
{
|
||||||
@@ -282,16 +307,17 @@ template<typename T, std::size_t N>
|
|||||||
struct repeat<T, exactly<N>>
|
struct repeat<T, exactly<N>>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region<Cont> retval(loc);
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
for(std::size_t i=0; i<N; ++i)
|
for(std::size_t i=0; i<N; ++i)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc);
|
auto rslt = T::invoke(loc, msg);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(rslt.unwrap_err());
|
return err(rslt.unwrap_err());
|
||||||
}
|
}
|
||||||
retval += rslt.unwrap();
|
retval += rslt.unwrap();
|
||||||
@@ -308,24 +334,25 @@ template<typename T, std::size_t N>
|
|||||||
struct repeat<T, at_least<N>>
|
struct repeat<T, at_least<N>>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region<Cont> retval(loc);
|
||||||
|
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
for(std::size_t i=0; i<N; ++i)
|
for(std::size_t i=0; i<N; ++i)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc);
|
auto rslt = T::invoke(loc, msg);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(rslt.unwrap_err());
|
return err(rslt.unwrap_err());
|
||||||
}
|
}
|
||||||
retval += rslt.unwrap();
|
retval += rslt.unwrap();
|
||||||
}
|
}
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc);
|
auto rslt = T::invoke(loc, msg);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
return ok(std::move(retval));
|
return ok(std::move(retval));
|
||||||
@@ -343,12 +370,13 @@ template<typename T>
|
|||||||
struct repeat<T, unlimited>
|
struct repeat<T, unlimited>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
|
static result<region<Cont>, std::string>
|
||||||
|
invoke(location<Cont>& loc, const bool msg = false)
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region<Cont> retval(loc);
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc);
|
auto rslt = T::invoke(loc, msg);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
return ok(std::move(retval));
|
return ok(std::move(retval));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_DATETIME
|
#ifndef TOML11_DATETIME_HPP
|
||||||
#define TOML11_DATETIME
|
#define TOML11_DATETIME_HPP
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -25,20 +25,22 @@ inline std::tm localtime_s(const std::time_t* src)
|
|||||||
{
|
{
|
||||||
std::tm dst;
|
std::tm dst;
|
||||||
const auto result = ::localtime_r(src, &dst);
|
const auto result = ::localtime_r(src, &dst);
|
||||||
if(!result)
|
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||||
{
|
return dst;
|
||||||
throw std::runtime_error("localtime_r failed.");
|
}
|
||||||
}
|
#elif _MSC_VER
|
||||||
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
|
{
|
||||||
|
std::tm dst;
|
||||||
|
const auto result = ::localtime_s(&dst, src);
|
||||||
|
if (result) { throw std::runtime_error("localtime_s failed."); }
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// XXX: On Windows, std::localtime is thread-safe because they uses thread-local
|
|
||||||
// storage to store the instance of std::tm. On the other platforms, it may not
|
|
||||||
// be thread-safe.
|
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
const auto result = std::localtime(src);
|
const auto result = std::localtime(src);
|
||||||
if(!result) {throw std::runtime_error("localtime failed.");}
|
if (!result) { throw std::runtime_error("localtime failed."); }
|
||||||
return *result;
|
return *result;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -332,17 +334,10 @@ operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
|
|||||||
os << 'Z';
|
os << 'Z';
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
if(static_cast<int>(offset.hour) * static_cast<int>(offset.minute) < 0)
|
int minute = static_cast<int>(offset.hour) * 60 + offset.minute;
|
||||||
{
|
if(minute < 0){os << '-'; minute = std::abs(minute);} else {os << '+';}
|
||||||
const int min = static_cast<int>(offset.hour) * 60 + offset.minute;
|
os << std::setfill('0') << std::setw(2) << minute / 60 << ':';
|
||||||
if(min < 0){os << '-';} else {os << '+';}
|
os << std::setfill('0') << std::setw(2) << minute % 60;
|
||||||
os << std::setfill('0') << std::setw(2) << min / 60 << ':';
|
|
||||||
os << std::setfill('0') << std::setw(2) << min % 60;
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
if(offset.hour < 0){os << '-';} else {os << '+';}
|
|
||||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(offset.hour) << ':';
|
|
||||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(offset.minute);
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,12 +362,12 @@ struct local_datetime
|
|||||||
// can be used to get millisecond & microsecond information.
|
// can be used to get millisecond & microsecond information.
|
||||||
const auto t_diff = tp -
|
const auto t_diff = tp -
|
||||||
std::chrono::system_clock::from_time_t(std::mktime(&time));
|
std::chrono::system_clock::from_time_t(std::mktime(&time));
|
||||||
this->time.millisecond = std::chrono::duration_cast<
|
this->time.millisecond = static_cast<std::uint16_t>(
|
||||||
std::chrono::milliseconds>(t_diff).count();
|
std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
|
||||||
this->time.microsecond = std::chrono::duration_cast<
|
this->time.microsecond = static_cast<std::uint16_t>(
|
||||||
std::chrono::microseconds>(t_diff).count();
|
std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());
|
||||||
this->time.nanosecond = std::chrono::duration_cast<
|
this->time.nanosecond = static_cast<std::uint16_t>(
|
||||||
std::chrono::nanoseconds >(t_diff).count();
|
std::chrono::duration_cast<std::chrono::nanoseconds >(t_diff).count());
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit local_datetime(const std::time_t t)
|
explicit local_datetime(const std::time_t t)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_EXCEPTION
|
#ifndef TOML11_EXCEPTION_HPP
|
||||||
#define TOML11_EXCEPTION
|
#define TOML11_EXCEPTION_HPP
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|||||||
20
toml/from.hpp
Normal file
20
toml/from.hpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright Toru Niina 2019.
|
||||||
|
// Distributed under the MIT License.
|
||||||
|
#ifndef TOML11_FROM_HPP
|
||||||
|
#define TOML11_FROM_HPP
|
||||||
|
#include "traits.hpp"
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct from;
|
||||||
|
// {
|
||||||
|
// static T from_toml(const toml::value& v)
|
||||||
|
// {
|
||||||
|
// // User-defined conversions ...
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
} // toml
|
||||||
|
#endif // TOML11_FROM_HPP
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_FROM_TOML
|
#ifndef TOML11_FROM_TOML_HPP
|
||||||
#define TOML11_FROM_TOML
|
#define TOML11_FROM_TOML_HPP
|
||||||
#include "get.hpp"
|
#include "get.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
@@ -51,7 +51,7 @@ struct from_toml_tie_impl
|
|||||||
template<typename ... Ts>
|
template<typename ... Ts>
|
||||||
struct from_toml_tie_impl<0, Ts...>
|
struct from_toml_tie_impl<0, Ts...>
|
||||||
{
|
{
|
||||||
static void invoke(std::tuple<Ts& ...> tie, const toml::value& v)
|
static void invoke(std::tuple<Ts& ...>, const toml::value&)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
359
toml/get.hpp
359
toml/get.hpp
@@ -1,7 +1,8 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_GET
|
#ifndef TOML11_GET_HPP
|
||||||
#define TOML11_GET
|
#define TOML11_GET_HPP
|
||||||
|
#include "from.hpp"
|
||||||
#include "result.hpp"
|
#include "result.hpp"
|
||||||
#include "value.hpp"
|
#include "value.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -112,7 +113,7 @@ inline std::string get(value&& v)
|
|||||||
|
|
||||||
template<typename T, typename std::enable_if<
|
template<typename T, typename std::enable_if<
|
||||||
detail::is_chrono_duration<T>::value, std::nullptr_t>::type = nullptr>
|
detail::is_chrono_duration<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
inline T get(value& v)
|
inline T get(const value& v)
|
||||||
{
|
{
|
||||||
return std::chrono::duration_cast<T>(
|
return std::chrono::duration_cast<T>(
|
||||||
std::chrono::nanoseconds(v.cast<value_t::LocalTime>()));
|
std::chrono::nanoseconds(v.cast<value_t::LocalTime>()));
|
||||||
@@ -124,7 +125,7 @@ inline T get(value& v)
|
|||||||
template<typename T, typename std::enable_if<
|
template<typename T, typename std::enable_if<
|
||||||
std::is_same<std::chrono::system_clock::time_point, T>::value,
|
std::is_same<std::chrono::system_clock::time_point, T>::value,
|
||||||
std::nullptr_t>::type = nullptr>
|
std::nullptr_t>::type = nullptr>
|
||||||
inline T get(value& v)
|
inline T get(const value& v)
|
||||||
{
|
{
|
||||||
switch(v.type())
|
switch(v.type())
|
||||||
{
|
{
|
||||||
@@ -173,6 +174,20 @@ template<typename T, typename std::enable_if<detail::conjunction<
|
|||||||
>::value, std::nullptr_t>::type = nullptr>
|
>::value, std::nullptr_t>::type = nullptr>
|
||||||
T get(const toml::value& v);
|
T get(const toml::value& v);
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||||
|
detail::has_from_toml_method<T>, // but has from_toml(toml::value) memfn
|
||||||
|
std::is_default_constructible<T> // and default constructible
|
||||||
|
>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T get(const toml::value& v);
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>> // not a toml::value
|
||||||
|
>::value, std::nullptr_t>::type = nullptr,
|
||||||
|
std::size_t = sizeof(::toml::from<T>) // and has from<T> specialization
|
||||||
|
>
|
||||||
|
T get(const toml::value& v);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// array-like types; most likely STL container, like std::vector, etc.
|
// array-like types; most likely STL container, like std::vector, etc.
|
||||||
|
|
||||||
@@ -297,6 +312,29 @@ T get(const toml::value& v)
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// user-defined, but compatible types.
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||||
|
detail::has_from_toml_method<T>, // but has from_toml(toml::value) memfn
|
||||||
|
std::is_default_constructible<T> // and default constructible
|
||||||
|
>::value, std::nullptr_t>::type>
|
||||||
|
T get(const toml::value& v)
|
||||||
|
{
|
||||||
|
T ud;
|
||||||
|
ud.from_toml(v);
|
||||||
|
return ud;
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>> // not a toml::value
|
||||||
|
>::value, std::nullptr_t>::type, std::size_t> // and has from<T>
|
||||||
|
T get(const toml::value& v)
|
||||||
|
{
|
||||||
|
return ::toml::from<T>::from_toml(v);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// find and get
|
// find and get
|
||||||
|
|
||||||
@@ -382,13 +420,14 @@ find(toml::value&& v, const toml::key& ky)
|
|||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// get_or
|
// get_or(value, fallback)
|
||||||
|
|
||||||
template<typename T>
|
// ----------------------------------------------------------------------------
|
||||||
decltype(::toml::get<typename std::remove_cv<
|
// specialization for the exact toml types (return type becomes lvalue ref)
|
||||||
typename std::remove_reference<T>::type>::type>(
|
|
||||||
std::declval<const toml::value&>()))
|
template<typename T, typename std::enable_if<
|
||||||
get_or(const toml::value& v, T&& opt)
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T const& get_or(const toml::value& v, const T& opt)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -397,14 +436,12 @@ get_or(const toml::value& v, T&& opt)
|
|||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
return std::forward<T>(opt);
|
return opt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T, typename std::enable_if<
|
||||||
decltype(::toml::get<typename std::remove_cv<
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
typename std::remove_reference<T>::type>::type>(
|
T& get_or(toml::value& v, T& opt)
|
||||||
std::declval<toml::value&>()))
|
|
||||||
get_or(toml::value& v, T&& opt)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -413,77 +450,333 @@ get_or(toml::value& v, T&& opt)
|
|||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
return std::forward<T>(opt);
|
return opt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T, typename std::enable_if<
|
||||||
decltype(::toml::get<typename std::remove_cv<
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
typename std::remove_reference<T>::type>::type>(
|
T&& get_or(toml::value&& v, T&& opt)
|
||||||
std::declval<toml::value&&>()))
|
|
||||||
get_or(toml::value&& v, T&& opt)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return get<typename std::remove_cv<
|
return get<typename std::remove_cv<
|
||||||
typename std::remove_reference<T>::type>::type>(std::move(v));
|
typename std::remove_reference<T>::type>::type>(v);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
return std::forward<T>(opt);
|
return opt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// specialization for std::string (return type becomes lvalue ref)
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string const& get_or(const toml::value& v, const T& opt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return get<std::string>(v);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string& get_or(toml::value& v, T& opt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return get<std::string>(v);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string get_or(toml::value&& v, T&& opt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return get<std::string>(v);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
|
||||||
|
std::nullptr_t>::type = nullptr>
|
||||||
|
std::string get_or(const toml::value& v, T&& opt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return get<std::string>(v);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return std::string(opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// others (require type conversion and return type cannot be lvalue reference)
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>,
|
||||||
|
detail::negation<std::is_same<T, std::string>>,
|
||||||
|
detail::negation<detail::is_string_literal<typename std::remove_reference<T>::type>>
|
||||||
|
>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T get_or(const toml::value& v, T&& opt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return get<typename std::remove_cv<
|
||||||
|
typename std::remove_reference<T>::type>::type>(v);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// get_or(table, key, fallback)
|
||||||
|
//
|
||||||
|
// DEPRECATED: use find_or instead.
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
TOML11_MARK_AS_DEPRECATED("use toml::find_or(table, key, opt) instead.")
|
||||||
auto get_or(const toml::table& tab, const toml::key& ky, T&& opt)
|
auto get_or(const toml::table& tab, const toml::key& ky, T&& opt)
|
||||||
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
|
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
|
||||||
{
|
{
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
|
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
TOML11_MARK_AS_DEPRECATED("use toml::find_or(table, key, opt) instead.")
|
||||||
auto get_or(toml::table& tab, const toml::key& ky, T&& opt)
|
auto get_or(toml::table& tab, const toml::key& ky, T&& opt)
|
||||||
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
|
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
|
||||||
{
|
{
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
return ::toml::get_or(tab[ky], std::forward<T>(opt));
|
return ::toml::get_or(tab[ky], std::forward<T>(opt));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
TOML11_MARK_AS_DEPRECATED("use toml::find_or(table, key, opt) instead.")
|
||||||
auto get_or(toml::table&& tab, const toml::key& ky, T&& opt)
|
auto get_or(toml::table&& tab, const toml::key& ky, T&& opt)
|
||||||
-> decltype(get_or(std::declval<value&&>(), std::forward<T>(opt)))
|
-> decltype(get_or(std::declval<value&&>(), std::forward<T>(opt)))
|
||||||
{
|
{
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
return ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
|
return ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
TOML11_MARK_AS_DEPRECATED("use toml::find_or(value, key, opt) instead.")
|
||||||
auto get_or(const toml::value& v, const toml::key& ky, T&& opt)
|
auto get_or(const toml::value& v, const toml::key& ky, T&& opt)
|
||||||
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
|
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
|
||||||
{
|
{
|
||||||
if(v.type() != toml::value_t::Table){return std::forward<T>(opt);}
|
if(!v.is_table()) {return opt;}
|
||||||
const auto& tab = toml::get<toml::table>(v);
|
const auto& tab = toml::get<toml::table>(v);
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
|
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
TOML11_MARK_AS_DEPRECATED("use toml::find_or(value, key, opt) instead.")
|
||||||
auto get_or(toml::value& v, const toml::key& ky, T&& opt)
|
auto get_or(toml::value& v, const toml::key& ky, T&& opt)
|
||||||
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
|
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
|
||||||
{
|
{
|
||||||
if(v.type() != toml::value_t::Table){return std::forward<T>(opt);}
|
if(!v.is_table()) {return opt;}
|
||||||
auto& tab = toml::get<toml::table>(v);
|
auto& tab = toml::get<toml::table>(v);
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
return ::toml::get_or(tab[ky], std::forward<T>(opt));
|
return ::toml::get_or(tab[ky], std::forward<T>(opt));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
TOML11_MARK_AS_DEPRECATED("use toml::find_or(value, key, opt) instead.")
|
||||||
auto get_or(toml::value&& v, const toml::key& ky, T&& opt)
|
auto get_or(toml::value&& v, const toml::key& ky, T&& opt)
|
||||||
-> decltype(get_or(std::declval<value&&>(), std::forward<T>(opt)))
|
-> decltype(get_or(std::declval<value&&>(), std::forward<T>(opt)))
|
||||||
{
|
{
|
||||||
if(v.type() != toml::value_t::Table){return std::forward<T>(opt);}
|
if(!v.is_table()) {return opt;}
|
||||||
auto tab = toml::get<toml::table>(std::move(v));
|
auto tab = toml::get<toml::table>(std::move(v));
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
return ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
|
return ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// find_or(value, key, fallback)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// exact types (return type can be a reference)
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T const& find_or(const toml::value& v, const toml::key& ky, const T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
const auto& tab = toml::get<toml::table>(v);
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T& find_or(toml::value& v, const toml::key& ky, T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
auto& tab = toml::get<toml::table>(v);
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab[ky], opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T&& find_or(toml::value&& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
auto tab = toml::get<toml::table>(std::move(v));
|
||||||
|
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 std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string const& find_or(const toml::value& v, const toml::key& ky, const T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
const auto& tab = toml::get<toml::table>(v);
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), opt);
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string& find_or(toml::value& v, const toml::key& ky, T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
auto& tab = toml::get<toml::table>(v);
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab[ky], opt);
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string find_or(toml::value&& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
auto tab = toml::get<toml::table>(std::move(v));
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// string literal (deduced as std::string)
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
|
||||||
|
std::nullptr_t>::type = nullptr>
|
||||||
|
std::string find_or(const toml::value& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
const auto& tab = toml::get<toml::table>(v);
|
||||||
|
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 std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>,
|
||||||
|
detail::negation<std::is_same<T, std::string>>,
|
||||||
|
detail::negation<detail::is_string_literal<typename std::remove_reference<T>::type>>
|
||||||
|
>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T find_or(const toml::value& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
const auto& tab = toml::get<toml::table>(v);
|
||||||
|
if(tab.count(ky) == 0) {return 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 std::enable_if<
|
||||||
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T const& find_or(const toml::table& tab, const toml::key& ky, const T& opt)
|
||||||
|
{
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T& find_or(toml::table& tab, const toml::key& ky, T& opt)
|
||||||
|
{
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab[ky], opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T&& find_or(toml::table&& tab, const toml::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 std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string const& find_or(const toml::table& tab, const toml::key& ky, const T& opt)
|
||||||
|
{
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), opt);
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string& find_or(toml::table& tab, const toml::key& ky, T& opt)
|
||||||
|
{
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab[ky], opt);
|
||||||
|
}
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
std::string find_or(toml::table&& tab, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// string literal (deduced as std::string)
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
|
||||||
|
std::nullptr_t>::type = nullptr>
|
||||||
|
std::string find_or(const toml::table& tab, const toml::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 std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>,
|
||||||
|
detail::negation<std::is_same<T, std::string>>,
|
||||||
|
detail::negation<detail::is_string_literal<typename std::remove_reference<T>::type>>
|
||||||
|
>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
T find_or(const toml::table& tab, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), std::forward<T>(opt));
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// expect
|
// expect
|
||||||
|
|
||||||
|
|||||||
20
toml/into.hpp
Normal file
20
toml/into.hpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright Toru Niina 2019.
|
||||||
|
// Distributed under the MIT License.
|
||||||
|
#ifndef TOML11_INTO_HPP
|
||||||
|
#define TOML11_INTO_HPP
|
||||||
|
#include "traits.hpp"
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct into;
|
||||||
|
// {
|
||||||
|
// static toml::value into_toml(const T& user_defined_type)
|
||||||
|
// {
|
||||||
|
// // User-defined conversions ...
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
} // toml
|
||||||
|
#endif // TOML11_INTO_HPP
|
||||||
91
toml/literal.hpp
Normal file
91
toml/literal.hpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright Toru Niina 2019.
|
||||||
|
// Distributed under the MIT License.
|
||||||
|
#ifndef TOML11_LITERAL_HPP
|
||||||
|
#define TOML11_LITERAL_HPP
|
||||||
|
#include "parser.hpp"
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
inline namespace literals
|
||||||
|
{
|
||||||
|
inline namespace toml_literals
|
||||||
|
{
|
||||||
|
|
||||||
|
inline ::toml::value operator""_toml(const char* str, std::size_t len)
|
||||||
|
{
|
||||||
|
::toml::detail::location<std::vector<char>>
|
||||||
|
loc(/* filename = */ std::string("TOML literal encoded in a C++ code"),
|
||||||
|
/* contents = */ std::vector<char>(str, str + len));
|
||||||
|
|
||||||
|
// if there are some comments or empty lines, skip them.
|
||||||
|
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
|
||||||
|
::toml::detail::maybe<::toml::detail::lex_ws>,
|
||||||
|
::toml::detail::maybe<::toml::detail::lex_comment>,
|
||||||
|
::toml::detail::lex_newline
|
||||||
|
>, ::toml::detail::at_least<1>>;
|
||||||
|
skip_line::invoke(loc);
|
||||||
|
|
||||||
|
// if there are some whitespaces before a value, skip them.
|
||||||
|
using skip_ws = ::toml::detail::repeat<
|
||||||
|
::toml::detail::lex_ws, ::toml::detail::at_least<1>>;
|
||||||
|
skip_ws::invoke(loc);
|
||||||
|
|
||||||
|
// to distinguish arrays and tables, first check it is a table or not.
|
||||||
|
//
|
||||||
|
// "[1,2,3]"_toml; // this is an array
|
||||||
|
// "[table]"_toml; // a table that has an empty table named "table" inside.
|
||||||
|
// "[[1,2,3]]"_toml; // this is an array of arrays
|
||||||
|
// "[[table]]"_toml; // this is a table that has an array of tables inside.
|
||||||
|
//
|
||||||
|
// "[[1]]"_toml; // this can be both... (currently it becomes a table)
|
||||||
|
// "1 = [{}]"_toml; // this is a table that has an array of table named 1.
|
||||||
|
// "[[1,]]"_toml; // this is an array of arrays.
|
||||||
|
// "[[1],]"_toml; // this also.
|
||||||
|
|
||||||
|
const auto the_front = loc.iter();
|
||||||
|
|
||||||
|
const bool is_table_key = ::toml::detail::lex_std_table::invoke(loc);
|
||||||
|
loc.reset(the_front);
|
||||||
|
|
||||||
|
const bool is_aots_key = ::toml::detail::lex_array_table::invoke(loc);
|
||||||
|
loc.reset(the_front);
|
||||||
|
|
||||||
|
// If it is neither a table-key or a array-of-table-key, it may be a value.
|
||||||
|
if(!is_table_key && !is_aots_key)
|
||||||
|
{
|
||||||
|
if(auto data = ::toml::detail::parse_value(loc))
|
||||||
|
{
|
||||||
|
return data.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that still it can be a table, because the literal might be something
|
||||||
|
// like the following.
|
||||||
|
// ```cpp
|
||||||
|
// R"( // c++11 raw string literals
|
||||||
|
// key = "value"
|
||||||
|
// int = 42
|
||||||
|
// )"_toml;
|
||||||
|
// ```
|
||||||
|
// It is a valid toml file.
|
||||||
|
// It should be parsed as if we parse a file with this content.
|
||||||
|
|
||||||
|
if(auto data = ::toml::detail::parse_toml_file(loc))
|
||||||
|
{
|
||||||
|
loc.reset(loc.begin()); // rollback to the top of the literal
|
||||||
|
// skip needless characters for error message
|
||||||
|
skip_line::invoke(loc); // skip the first several needless lines
|
||||||
|
skip_ws::invoke(loc); // skip the first several needless whitespaces
|
||||||
|
return ::toml::value(std::move(data.unwrap()),
|
||||||
|
::toml::detail::region<std::vector<char>>(std::move(loc)));
|
||||||
|
}
|
||||||
|
else // none of them.
|
||||||
|
{
|
||||||
|
throw ::toml::syntax_error(data.unwrap_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // toml_literals
|
||||||
|
} // literals
|
||||||
|
} // toml
|
||||||
|
#endif//TOML11_LITERAL_HPP
|
||||||
301
toml/parser.hpp
301
toml/parser.hpp
@@ -33,7 +33,7 @@ parse_boolean(location<Container>& loc)
|
|||||||
{{std::addressof(reg), "invalid token"}}));
|
{{std::addressof(reg), "invalid token"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loc.iter() = first; //rollback
|
loc.reset(first); //rollback
|
||||||
return err(format_underline("[error] toml::parse_boolean: ",
|
return err(format_underline("[error] toml::parse_boolean: ",
|
||||||
{{std::addressof(loc), "the next token is not a boolean"}}));
|
{{std::addressof(loc), "the next token is not a boolean"}}));
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ parse_binary_integer(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error] toml::parse_binary_integer:",
|
return err(format_underline("[error] toml::parse_binary_integer:",
|
||||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ parse_octal_integer(location<Container>& loc)
|
|||||||
iss >> std::oct >> retval;
|
iss >> std::oct >> retval;
|
||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error] toml::parse_octal_integer:",
|
return err(format_underline("[error] toml::parse_octal_integer:",
|
||||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ parse_hexadecimal_integer(location<Container>& loc)
|
|||||||
iss >> std::hex >> retval;
|
iss >> std::hex >> retval;
|
||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error] toml::parse_hexadecimal_integer",
|
return err(format_underline("[error] toml::parse_hexadecimal_integer",
|
||||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||||
}
|
}
|
||||||
@@ -116,10 +116,28 @@ parse_integer(location<Container>& loc)
|
|||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
if(first != loc.end() && *first == '0')
|
if(first != loc.end() && *first == '0')
|
||||||
{
|
{
|
||||||
if(const auto bin = parse_binary_integer (loc)) {return bin;}
|
const auto second = std::next(first);
|
||||||
if(const auto oct = parse_octal_integer (loc)) {return oct;}
|
if(second == loc.end()) // the token is just zero.
|
||||||
if(const auto hex = parse_hexadecimal_integer(loc)) {return hex;}
|
{
|
||||||
// else, maybe just zero.
|
return ok(std::make_pair(0, region<Container>(loc, first, second)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*second == 'b') {return parse_binary_integer (loc);} // 0b1100
|
||||||
|
if(*second == 'o') {return parse_octal_integer (loc);} // 0o775
|
||||||
|
if(*second == 'x') {return parse_hexadecimal_integer(loc);} // 0xC0FFEE
|
||||||
|
|
||||||
|
if(std::isdigit(*second))
|
||||||
|
{
|
||||||
|
return err(format_underline("[error] toml::parse_integer: "
|
||||||
|
"leading zero in an Integer is not allowed.",
|
||||||
|
{{std::addressof(loc), "leading zero"}}));
|
||||||
|
}
|
||||||
|
else if(std::isalpha(*second))
|
||||||
|
{
|
||||||
|
return err(format_underline("[error] toml::parse_integer: "
|
||||||
|
"unknown integer prefix appeared.",
|
||||||
|
{{std::addressof(loc), "none of 0x, 0o, 0b"}}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(const auto token = lex_dec_int::invoke(loc))
|
if(const auto token = lex_dec_int::invoke(loc))
|
||||||
@@ -132,7 +150,7 @@ parse_integer(location<Container>& loc)
|
|||||||
iss >> retval;
|
iss >> retval;
|
||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error] toml::parse_integer: ",
|
return err(format_underline("[error] toml::parse_integer: ",
|
||||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||||
}
|
}
|
||||||
@@ -221,7 +239,7 @@ parse_floating(location<Container>& loc)
|
|||||||
iss >> v;
|
iss >> v;
|
||||||
return ok(std::make_pair(v, token.unwrap()));
|
return ok(std::make_pair(v, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error] toml::parse_floating: ",
|
return err(format_underline("[error] toml::parse_floating: ",
|
||||||
{{std::addressof(loc), "the next token is not a float"}}));
|
{{std::addressof(loc), "the next token is not a float"}}));
|
||||||
}
|
}
|
||||||
@@ -250,11 +268,11 @@ std::string read_utf8_codepoint(const region<Container>& reg,
|
|||||||
{
|
{
|
||||||
if(0xD800 <= codepoint && codepoint <= 0xDFFF)
|
if(0xD800 <= codepoint && codepoint <= 0xDFFF)
|
||||||
{
|
{
|
||||||
std::cerr << format_underline("[warning] "
|
throw syntax_error(format_underline("[error] "
|
||||||
"toml::read_utf8_codepoint: codepoints in the range "
|
"toml::read_utf8_codepoint: codepoints in the range "
|
||||||
"[0xD800, 0xDFFF] are not valid UTF-8.", {{
|
"[0xD800, 0xDFFF] are not valid UTF-8.", {{
|
||||||
std::addressof(loc), "not a valid UTF-8 codepoint"
|
std::addressof(loc), "not a valid UTF-8 codepoint"
|
||||||
}}) << std::endl;
|
}}));
|
||||||
}
|
}
|
||||||
assert(codepoint < 0xD800 || 0xDFFF < codepoint);
|
assert(codepoint < 0xD800 || 0xDFFF < codepoint);
|
||||||
// 1110yyyy 10yxxxxx 10xxxxxx
|
// 1110yyyy 10yxxxxx 10xxxxxx
|
||||||
@@ -262,15 +280,8 @@ std::string read_utf8_codepoint(const region<Container>& reg,
|
|||||||
character += static_cast<unsigned char>(0x80|(codepoint >> 6 & 0x3F));
|
character += static_cast<unsigned char>(0x80|(codepoint >> 6 & 0x3F));
|
||||||
character += static_cast<unsigned char>(0x80|(codepoint & 0x3F));
|
character += static_cast<unsigned char>(0x80|(codepoint & 0x3F));
|
||||||
}
|
}
|
||||||
else if(codepoint < 0x200000) // U+010000 ... U+1FFFFF
|
else if(codepoint < 0x110000) // U+010000 ... U+10FFFF
|
||||||
{
|
{
|
||||||
if(0x10FFFF < codepoint) // out of Unicode region
|
|
||||||
{
|
|
||||||
std::cerr << format_underline("[error] "
|
|
||||||
"toml::read_utf8_codepoint: input codepoint is too large to "
|
|
||||||
"decode as a unicode character.", {{std::addressof(loc),
|
|
||||||
"should be in [0x00..0x10FFFF]"}}) << std::endl;
|
|
||||||
}
|
|
||||||
// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
|
// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
|
||||||
character += static_cast<unsigned char>(0xF0| codepoint >> 18);
|
character += static_cast<unsigned char>(0xF0| codepoint >> 18);
|
||||||
character += static_cast<unsigned char>(0x80|(codepoint >> 12 & 0x3F));
|
character += static_cast<unsigned char>(0x80|(codepoint >> 12 & 0x3F));
|
||||||
@@ -279,9 +290,9 @@ std::string read_utf8_codepoint(const region<Container>& reg,
|
|||||||
}
|
}
|
||||||
else // out of UTF-8 region
|
else // out of UTF-8 region
|
||||||
{
|
{
|
||||||
throw std::range_error(format_underline(concat_to_string("[error] "
|
throw syntax_error(format_underline("[error] toml::read_utf8_codepoint:"
|
||||||
"input codepoint (", str, ") is too large to encode as utf-8."),
|
" input codepoint is too large.",
|
||||||
{{std::addressof(reg), "should be in [0x00..0x10FFFF]"}}));
|
{{std::addressof(loc), "should be in [0x00..0x10FFFF]"}}));
|
||||||
}
|
}
|
||||||
return character;
|
return character;
|
||||||
}
|
}
|
||||||
@@ -295,16 +306,16 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
|||||||
return err(format_underline("[error]: toml::parse_escape_sequence: ", {{
|
return err(format_underline("[error]: toml::parse_escape_sequence: ", {{
|
||||||
std::addressof(loc), "the next token is not a backslash \"\\\""}}));
|
std::addressof(loc), "the next token is not a backslash \"\\\""}}));
|
||||||
}
|
}
|
||||||
++loc.iter();
|
loc.advance();
|
||||||
switch(*loc.iter())
|
switch(*loc.iter())
|
||||||
{
|
{
|
||||||
case '\\':{++loc.iter(); return ok(std::string("\\"));}
|
case '\\':{loc.advance(); return ok(std::string("\\"));}
|
||||||
case '"' :{++loc.iter(); return ok(std::string("\""));}
|
case '"' :{loc.advance(); return ok(std::string("\""));}
|
||||||
case 'b' :{++loc.iter(); return ok(std::string("\b"));}
|
case 'b' :{loc.advance(); return ok(std::string("\b"));}
|
||||||
case 't' :{++loc.iter(); return ok(std::string("\t"));}
|
case 't' :{loc.advance(); return ok(std::string("\t"));}
|
||||||
case 'n' :{++loc.iter(); return ok(std::string("\n"));}
|
case 'n' :{loc.advance(); return ok(std::string("\n"));}
|
||||||
case 'f' :{++loc.iter(); return ok(std::string("\f"));}
|
case 'f' :{loc.advance(); return ok(std::string("\f"));}
|
||||||
case 'r' :{++loc.iter(); return ok(std::string("\r"));}
|
case 'r' :{loc.advance(); return ok(std::string("\r"));}
|
||||||
case 'u' :
|
case 'u' :
|
||||||
{
|
{
|
||||||
if(const auto token = lex_escape_unicode_short::invoke(loc))
|
if(const auto token = lex_escape_unicode_short::invoke(loc))
|
||||||
@@ -315,7 +326,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
|||||||
{
|
{
|
||||||
return err(format_underline("[error] parse_escape_sequence: "
|
return err(format_underline("[error] parse_escape_sequence: "
|
||||||
"invalid token found in UTF-8 codepoint uXXXX.",
|
"invalid token found in UTF-8 codepoint uXXXX.",
|
||||||
{{std::addressof(loc), token.unwrap_err()}}));
|
{{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'U':
|
case 'U':
|
||||||
@@ -328,7 +339,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
|||||||
{
|
{
|
||||||
return err(format_underline("[error] parse_escape_sequence: "
|
return err(format_underline("[error] parse_escape_sequence: "
|
||||||
"invalid token found in UTF-8 codepoint Uxxxxxxxx",
|
"invalid token found in UTF-8 codepoint Uxxxxxxxx",
|
||||||
{{std::addressof(loc), token.unwrap_err()}}));
|
{{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,7 +349,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
|||||||
"escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}},
|
"escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}},
|
||||||
/* Hints = */{"if you want to write backslash as just one backslash, "
|
/* Hints = */{"if you want to write backslash as just one backslash, "
|
||||||
"use literal string like: regex = '<\\i\\c*\\s*>'"});
|
"use literal string like: regex = '<\\i\\c*\\s*>'"});
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(msg);
|
return err(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +361,7 @@ parse_ml_basic_string(location<Container>& loc)
|
|||||||
if(const auto token = lex_ml_basic_string::invoke(loc))
|
if(const auto token = lex_ml_basic_string::invoke(loc))
|
||||||
{
|
{
|
||||||
auto inner_loc = loc;
|
auto inner_loc = loc;
|
||||||
inner_loc.iter() = first;
|
inner_loc.reset(first);
|
||||||
|
|
||||||
std::string retval;
|
std::string retval;
|
||||||
retval.reserve(token.unwrap().size());
|
retval.reserve(token.unwrap().size());
|
||||||
@@ -394,8 +405,10 @@ parse_ml_basic_string(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(token.unwrap_err());
|
return err(format_underline("[error] toml::parse_ml_basic_string: "
|
||||||
|
"the next token is not a multiline string",
|
||||||
|
{{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +420,7 @@ parse_basic_string(location<Container>& loc)
|
|||||||
if(const auto token = lex_basic_string::invoke(loc))
|
if(const auto token = lex_basic_string::invoke(loc))
|
||||||
{
|
{
|
||||||
auto inner_loc = loc;
|
auto inner_loc = loc;
|
||||||
inner_loc.iter() = first;
|
inner_loc.reset(first);
|
||||||
|
|
||||||
auto quot = lex_quotation_mark::invoke(inner_loc);
|
auto quot = lex_quotation_mark::invoke(inner_loc);
|
||||||
if(!quot)
|
if(!quot)
|
||||||
@@ -443,8 +456,10 @@ parse_basic_string(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first; // rollback
|
loc.reset(first); // rollback
|
||||||
return err(token.unwrap_err());
|
return err(format_underline("[error] toml::parse_basic_string: "
|
||||||
|
"the next token is not a string",
|
||||||
|
{{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,8 +497,10 @@ parse_ml_literal_string(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first; // rollback
|
loc.reset(first); // rollback
|
||||||
return err(token.unwrap_err());
|
return err(format_underline("[error] toml::parse_ml_literal_string: "
|
||||||
|
"the next token is not a multiline literal string",
|
||||||
|
{{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,8 +536,10 @@ parse_literal_string(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first; // rollback
|
loc.reset(first); // rollback
|
||||||
return err(token.unwrap_err());
|
return err(format_underline("[error] toml::parse_literal_string: "
|
||||||
|
"the next token is not a literal string",
|
||||||
|
{{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,10 +547,30 @@ template<typename Container>
|
|||||||
result<std::pair<toml::string, region<Container>>, std::string>
|
result<std::pair<toml::string, region<Container>>, std::string>
|
||||||
parse_string(location<Container>& loc)
|
parse_string(location<Container>& loc)
|
||||||
{
|
{
|
||||||
if(const auto rslt = parse_ml_basic_string(loc)) {return rslt;}
|
if(loc.iter() != loc.end() && *(loc.iter()) == '"')
|
||||||
if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;}
|
{
|
||||||
if(const auto rslt = parse_basic_string(loc)) {return rslt;}
|
if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '"' &&
|
||||||
if(const auto rslt = parse_literal_string(loc)) {return rslt;}
|
loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '"')
|
||||||
|
{
|
||||||
|
return parse_ml_basic_string(loc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return parse_basic_string(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(loc.iter() != loc.end() && *(loc.iter()) == '\'')
|
||||||
|
{
|
||||||
|
if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '\'' &&
|
||||||
|
loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '\'')
|
||||||
|
{
|
||||||
|
return parse_ml_literal_string(loc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return parse_literal_string(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
return err(format_underline("[error] toml::parse_string: ",
|
return err(format_underline("[error] toml::parse_string: ",
|
||||||
{{std::addressof(loc), "the next token is not a string"}}));
|
{{std::addressof(loc), "the next token is not a string"}}));
|
||||||
}
|
}
|
||||||
@@ -555,7 +594,7 @@ parse_local_date(location<Container>& loc)
|
|||||||
"toml::parse_inner_local_date: invalid year format",
|
"toml::parse_inner_local_date: invalid year format",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), msg}}));
|
||||||
}
|
}
|
||||||
++inner_loc.iter();
|
inner_loc.advance();
|
||||||
const auto m = lex_date_month::invoke(inner_loc);
|
const auto m = lex_date_month::invoke(inner_loc);
|
||||||
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
|
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
|
||||||
{
|
{
|
||||||
@@ -566,7 +605,7 @@ parse_local_date(location<Container>& loc)
|
|||||||
"toml::parse_local_date: invalid month format",
|
"toml::parse_local_date: invalid month format",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), msg}}));
|
||||||
}
|
}
|
||||||
++inner_loc.iter();
|
inner_loc.advance();
|
||||||
const auto d = lex_date_mday::invoke(inner_loc);
|
const auto d = lex_date_mday::invoke(inner_loc);
|
||||||
if(!d)
|
if(!d)
|
||||||
{
|
{
|
||||||
@@ -583,7 +622,7 @@ parse_local_date(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error]: toml::parse_local_date: ",
|
return err(format_underline("[error]: toml::parse_local_date: ",
|
||||||
{{std::addressof(loc), "the next token is not a local_date"}}));
|
{{std::addressof(loc), "the next token is not a local_date"}}));
|
||||||
}
|
}
|
||||||
@@ -608,7 +647,7 @@ parse_local_time(location<Container>& loc)
|
|||||||
"toml::parse_local_time: invalid year format",
|
"toml::parse_local_time: invalid year format",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), msg}}));
|
||||||
}
|
}
|
||||||
++inner_loc.iter();
|
inner_loc.advance();
|
||||||
const auto m = lex_time_minute::invoke(inner_loc);
|
const auto m = lex_time_minute::invoke(inner_loc);
|
||||||
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
|
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
|
||||||
{
|
{
|
||||||
@@ -619,7 +658,7 @@ parse_local_time(location<Container>& loc)
|
|||||||
"toml::parse_local_time: invalid month format",
|
"toml::parse_local_time: invalid month format",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), msg}}));
|
||||||
}
|
}
|
||||||
++inner_loc.iter();
|
inner_loc.advance();
|
||||||
const auto s = lex_time_second::invoke(inner_loc);
|
const auto s = lex_time_second::invoke(inner_loc);
|
||||||
if(!s)
|
if(!s)
|
||||||
{
|
{
|
||||||
@@ -668,7 +707,7 @@ parse_local_time(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error]: toml::parse_local_time: ",
|
return err(format_underline("[error]: toml::parse_local_time: ",
|
||||||
{{std::addressof(loc), "the next token is not a local_time"}}));
|
{{std::addressof(loc), "the next token is not a local_time"}}));
|
||||||
}
|
}
|
||||||
@@ -692,13 +731,14 @@ parse_local_datetime(location<Container>& loc)
|
|||||||
"toml::parse_local_datetime: invalid datetime format",
|
"toml::parse_local_datetime: invalid datetime format",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), msg}}));
|
||||||
}
|
}
|
||||||
const char delim = *(inner_loc.iter()++);
|
const char delim = *(inner_loc.iter());
|
||||||
if(delim != 'T' && delim != 't' && delim != ' ')
|
if(delim != 'T' && delim != 't' && delim != ' ')
|
||||||
{
|
{
|
||||||
throw internal_error(format_underline("[error]: "
|
throw internal_error(format_underline("[error]: "
|
||||||
"toml::parse_local_datetime: invalid datetime format",
|
"toml::parse_local_datetime: invalid datetime format",
|
||||||
{{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}));
|
{{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}));
|
||||||
}
|
}
|
||||||
|
inner_loc.advance();
|
||||||
const auto time = parse_local_time(inner_loc);
|
const auto time = parse_local_time(inner_loc);
|
||||||
if(!time)
|
if(!time)
|
||||||
{
|
{
|
||||||
@@ -712,7 +752,7 @@ parse_local_datetime(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error]: toml::parse_local_datetime: ",
|
return err(format_underline("[error]: toml::parse_local_datetime: ",
|
||||||
{{std::addressof(loc), "the next token is not a local_datetime"}}));
|
{{std::addressof(loc), "the next token is not a local_datetime"}}));
|
||||||
}
|
}
|
||||||
@@ -762,9 +802,9 @@ parse_offset_datetime(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(format_underline("[error]: toml::parse_offset_datetime: ",
|
return err(format_underline("[error]: toml::parse_offset_datetime: ",
|
||||||
{{std::addressof(loc), "the next token is not a local_datetime"}}));
|
{{std::addressof(loc), "the next token is not a offset_datetime"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -823,7 +863,7 @@ parse_key(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else if(*inner_loc.iter() == '.')
|
else if(*inner_loc.iter() == '.')
|
||||||
{
|
{
|
||||||
++inner_loc.iter(); // to skip `.`
|
inner_loc.advance(); // to skip `.`
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -834,7 +874,7 @@ parse_key(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
return ok(std::make_pair(keys, reg));
|
return ok(std::make_pair(keys, reg));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
|
|
||||||
// simple key -> foo
|
// simple key -> foo
|
||||||
if(const auto smpl = parse_simple_key(loc))
|
if(const auto smpl = parse_simple_key(loc))
|
||||||
@@ -863,7 +903,7 @@ parse_array(location<Container>& loc)
|
|||||||
{
|
{
|
||||||
return err("[error] toml::parse_array: token is not an array");
|
return err("[error] toml::parse_array: token is not an array");
|
||||||
}
|
}
|
||||||
++loc.iter();
|
loc.advance();
|
||||||
|
|
||||||
using lex_ws_comment_newline = repeat<
|
using lex_ws_comment_newline = repeat<
|
||||||
either<lex_wschar, lex_newline, lex_comment>, unlimited>;
|
either<lex_wschar, lex_newline, lex_comment>, unlimited>;
|
||||||
@@ -875,7 +915,7 @@ parse_array(location<Container>& loc)
|
|||||||
|
|
||||||
if(loc.iter() != loc.end() && *loc.iter() == ']')
|
if(loc.iter() != loc.end() && *loc.iter() == ']')
|
||||||
{
|
{
|
||||||
++loc.iter(); // skip ']'
|
loc.advance(); // skip ']'
|
||||||
return ok(std::make_pair(retval,
|
return ok(std::make_pair(retval,
|
||||||
region<Container>(loc, first, loc.iter())));
|
region<Container>(loc, first, loc.iter())));
|
||||||
}
|
}
|
||||||
@@ -885,7 +925,7 @@ parse_array(location<Container>& loc)
|
|||||||
if(!retval.empty() && retval.front().type() != val.as_ok().type())
|
if(!retval.empty() && retval.front().type() != val.as_ok().type())
|
||||||
{
|
{
|
||||||
auto array_start_loc = loc;
|
auto array_start_loc = loc;
|
||||||
array_start_loc.iter() = first;
|
array_start_loc.reset(first);
|
||||||
|
|
||||||
throw syntax_error(format_underline("[error] toml::parse_array: "
|
throw syntax_error(format_underline("[error] toml::parse_array: "
|
||||||
"type of elements should be the same each other.", {
|
"type of elements should be the same each other.", {
|
||||||
@@ -905,7 +945,7 @@ parse_array(location<Container>& loc)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto array_start_loc = loc;
|
auto array_start_loc = loc;
|
||||||
array_start_loc.iter() = first;
|
array_start_loc.reset(first);
|
||||||
|
|
||||||
throw syntax_error(format_underline("[error] toml::parse_array: "
|
throw syntax_error(format_underline("[error] toml::parse_array: "
|
||||||
"value having invalid format appeared in an array", {
|
"value having invalid format appeared in an array", {
|
||||||
@@ -921,14 +961,14 @@ parse_array(location<Container>& loc)
|
|||||||
lex_ws_comment_newline::invoke(loc);
|
lex_ws_comment_newline::invoke(loc);
|
||||||
if(loc.iter() != loc.end() && *loc.iter() == ']')
|
if(loc.iter() != loc.end() && *loc.iter() == ']')
|
||||||
{
|
{
|
||||||
++loc.iter(); // skip ']'
|
loc.advance(); // skip ']'
|
||||||
return ok(std::make_pair(retval,
|
return ok(std::make_pair(retval,
|
||||||
region<Container>(loc, first, loc.iter())));
|
region<Container>(loc, first, loc.iter())));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto array_start_loc = loc;
|
auto array_start_loc = loc;
|
||||||
array_start_loc.iter() = first;
|
array_start_loc.reset(first);
|
||||||
|
|
||||||
throw syntax_error(format_underline("[error] toml::parse_array:"
|
throw syntax_error(format_underline("[error] toml::parse_array:"
|
||||||
" missing array separator `,` after a value", {
|
" missing array separator `,` after a value", {
|
||||||
@@ -938,7 +978,7 @@ parse_array(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
throw syntax_error(format_underline("[error] toml::parse_array: "
|
throw syntax_error(format_underline("[error] toml::parse_array: "
|
||||||
"array did not closed by `]`",
|
"array did not closed by `]`",
|
||||||
{{std::addressof(loc), "should be closed"}}));
|
{{std::addressof(loc), "should be closed"}}));
|
||||||
@@ -957,7 +997,7 @@ parse_key_value_pair(location<Container>& loc)
|
|||||||
// key. then we need to show error as "empty key is not allowed".
|
// key. then we need to show error as "empty key is not allowed".
|
||||||
if(const auto keyval_sep = lex_keyval_sep::invoke(loc))
|
if(const auto keyval_sep = lex_keyval_sep::invoke(loc))
|
||||||
{
|
{
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
msg = format_underline("[error] toml::parse_key_value_pair: "
|
msg = format_underline("[error] toml::parse_key_value_pair: "
|
||||||
"empty key is not allowed.",
|
"empty key is not allowed.",
|
||||||
{{std::addressof(loc), "key expected before '='"}});
|
{{std::addressof(loc), "key expected before '='"}});
|
||||||
@@ -986,7 +1026,7 @@ parse_key_value_pair(location<Container>& loc)
|
|||||||
"missing key-value separator `=`",
|
"missing key-value separator `=`",
|
||||||
{{std::addressof(loc), "should be `=`"}});
|
{{std::addressof(loc), "should be `=`"}});
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(std::move(msg));
|
return err(std::move(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -995,11 +1035,11 @@ parse_key_value_pair(location<Container>& loc)
|
|||||||
if(!val)
|
if(!val)
|
||||||
{
|
{
|
||||||
std::string msg;
|
std::string msg;
|
||||||
loc.iter() = after_kvsp;
|
loc.reset(after_kvsp);
|
||||||
// check there is something not a comment/whitespace after `=`
|
// check there is something not a comment/whitespace after `=`
|
||||||
if(sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>::invoke(loc))
|
if(sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>::invoke(loc))
|
||||||
{
|
{
|
||||||
loc.iter() = after_kvsp;
|
loc.reset(after_kvsp);
|
||||||
msg = format_underline("[error] toml::parse_key_value_pair: "
|
msg = format_underline("[error] toml::parse_key_value_pair: "
|
||||||
"missing value after key-value separator '='",
|
"missing value after key-value separator '='",
|
||||||
{{std::addressof(loc), "expected value, but got nothing"}});
|
{{std::addressof(loc), "expected value, but got nothing"}});
|
||||||
@@ -1008,7 +1048,7 @@ parse_key_value_pair(location<Container>& loc)
|
|||||||
{
|
{
|
||||||
msg = std::move(val.unwrap_err());
|
msg = std::move(val.unwrap_err());
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
return err(msg);
|
return err(msg);
|
||||||
}
|
}
|
||||||
return ok(std::make_pair(std::move(key_reg.unwrap()),
|
return ok(std::make_pair(std::move(key_reg.unwrap()),
|
||||||
@@ -1035,6 +1075,7 @@ std::string format_dotted_keys(InputIterator first, const InputIterator last)
|
|||||||
template<typename Container>
|
template<typename Container>
|
||||||
result<std::pair<std::vector<key>, region<Container>>, std::string>
|
result<std::pair<std::vector<key>, region<Container>>, std::string>
|
||||||
parse_table_key(location<Container>& loc);
|
parse_table_key(location<Container>& loc);
|
||||||
|
|
||||||
// The following toml file is allowed.
|
// The following toml file is allowed.
|
||||||
// ```toml
|
// ```toml
|
||||||
// [a.b.c] # here, table `a` has element `b`.
|
// [a.b.c] # here, table `a` has element `b`.
|
||||||
@@ -1325,14 +1366,14 @@ parse_inline_table(location<Container>& loc)
|
|||||||
return err(format_underline("[error] toml::parse_inline_table: ",
|
return err(format_underline("[error] toml::parse_inline_table: ",
|
||||||
{{std::addressof(loc), "the next token is not an inline table"}}));
|
{{std::addressof(loc), "the next token is not an inline table"}}));
|
||||||
}
|
}
|
||||||
++loc.iter();
|
loc.advance();
|
||||||
// it starts from "{". it should be formatted as inline-table
|
// it starts from "{". it should be formatted as inline-table
|
||||||
while(loc.iter() != loc.end())
|
while(loc.iter() != loc.end())
|
||||||
{
|
{
|
||||||
maybe<lex_ws>::invoke(loc);
|
maybe<lex_ws>::invoke(loc);
|
||||||
if(loc.iter() != loc.end() && *loc.iter() == '}')
|
if(loc.iter() != loc.end() && *loc.iter() == '}')
|
||||||
{
|
{
|
||||||
++loc.iter(); // skip `}`
|
loc.advance(); // skip `}`
|
||||||
return ok(std::make_pair(
|
return ok(std::make_pair(
|
||||||
retval, region<Container>(loc, first, loc.iter())));
|
retval, region<Container>(loc, first, loc.iter())));
|
||||||
}
|
}
|
||||||
@@ -1361,24 +1402,70 @@ parse_inline_table(location<Container>& loc)
|
|||||||
maybe<lex_ws>::invoke(loc);
|
maybe<lex_ws>::invoke(loc);
|
||||||
if(loc.iter() != loc.end() && *loc.iter() == '}')
|
if(loc.iter() != loc.end() && *loc.iter() == '}')
|
||||||
{
|
{
|
||||||
++loc.iter(); // skip `}`
|
loc.advance(); // skip `}`
|
||||||
return ok(std::make_pair(
|
return ok(std::make_pair(
|
||||||
retval, region<Container>(loc, first, loc.iter())));
|
retval, region<Container>(loc, first, loc.iter())));
|
||||||
}
|
}
|
||||||
|
else if(*loc.iter() == '#' || *loc.iter() == '\r' || *loc.iter() == '\n')
|
||||||
|
{
|
||||||
|
throw syntax_error(format_underline("[error] "
|
||||||
|
"toml::parse_inline_table: missing curly brace `}`",
|
||||||
|
{{std::addressof(loc), "should be `}`"}}));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw syntax_error(format_underline("[error] "
|
throw syntax_error(format_underline("[error] "
|
||||||
"toml:::parse_inline_table: missing table separator `,` ",
|
"toml::parse_inline_table: missing table separator `,` ",
|
||||||
{{std::addressof(loc), "should be `,`"}}));
|
{{std::addressof(loc), "should be `,`"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.reset(first);
|
||||||
throw syntax_error(format_underline("[error] toml::parse_inline_table: "
|
throw syntax_error(format_underline("[error] toml::parse_inline_table: "
|
||||||
"inline table did not closed by `}`",
|
"inline table did not closed by `}`",
|
||||||
{{std::addressof(loc), "should be closed"}}));
|
{{std::addressof(loc), "should be closed"}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
value_t guess_number_type(const location<Container>& l)
|
||||||
|
{
|
||||||
|
location<Container> loc = l;
|
||||||
|
|
||||||
|
if(lex_offset_date_time::invoke(loc)) {return value_t::OffsetDatetime;}
|
||||||
|
loc.reset(l.iter());
|
||||||
|
|
||||||
|
if(lex_local_date_time::invoke(loc)) {return value_t::LocalDatetime;}
|
||||||
|
loc.reset(l.iter());
|
||||||
|
|
||||||
|
if(lex_local_date::invoke(loc)) {return value_t::LocalDate;}
|
||||||
|
loc.reset(l.iter());
|
||||||
|
|
||||||
|
if(lex_local_time::invoke(loc)) {return value_t::LocalTime;}
|
||||||
|
loc.reset(l.iter());
|
||||||
|
|
||||||
|
if(lex_float::invoke(loc)) {return value_t::Float;}
|
||||||
|
loc.reset(l.iter());
|
||||||
|
|
||||||
|
return value_t::Integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
value_t guess_value_type(const location<Container>& loc)
|
||||||
|
{
|
||||||
|
switch(*loc.iter())
|
||||||
|
{
|
||||||
|
case '"' : {return value_t::String; }
|
||||||
|
case '\'': {return value_t::String; }
|
||||||
|
case 't' : {return value_t::Boolean;}
|
||||||
|
case 'f' : {return value_t::Boolean;}
|
||||||
|
case '[' : {return value_t::Array; }
|
||||||
|
case '{' : {return value_t::Table; }
|
||||||
|
case 'i' : {return value_t::Float; } // inf.
|
||||||
|
case 'n' : {return value_t::Float; } // nan.
|
||||||
|
default : {return guess_number_type(loc);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
result<value, std::string> parse_value(location<Container>& loc)
|
result<value, std::string> parse_value(location<Container>& loc)
|
||||||
{
|
{
|
||||||
@@ -1388,31 +1475,27 @@ result<value, std::string> parse_value(location<Container>& loc)
|
|||||||
return err(format_underline("[error] toml::parse_value: input is empty",
|
return err(format_underline("[error] toml::parse_value: input is empty",
|
||||||
{{std::addressof(loc), ""}}));
|
{{std::addressof(loc), ""}}));
|
||||||
}
|
}
|
||||||
if(auto r = parse_string (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_array (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_inline_table (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_boolean (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_offset_datetime(loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_local_datetime (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_local_date (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_local_time (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_floating (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
if(auto r = parse_integer (loc))
|
|
||||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
|
||||||
|
|
||||||
const auto msg = format_underline("[error] toml::parse_value: "
|
switch(guess_value_type(loc))
|
||||||
"unknown token appeared", {{std::addressof(loc), "unknown"}});
|
{
|
||||||
loc.iter() = first;
|
case value_t::Boolean : {return parse_boolean(loc); }
|
||||||
return err(msg);
|
case value_t::Integer : {return parse_integer(loc); }
|
||||||
|
case value_t::Float : {return parse_floating(loc); }
|
||||||
|
case value_t::String : {return parse_string(loc); }
|
||||||
|
case value_t::OffsetDatetime : {return parse_offset_datetime(loc);}
|
||||||
|
case value_t::LocalDatetime : {return parse_local_datetime(loc); }
|
||||||
|
case value_t::LocalDate : {return parse_local_date(loc); }
|
||||||
|
case value_t::LocalTime : {return parse_local_time(loc); }
|
||||||
|
case value_t::Array : {return parse_array(loc); }
|
||||||
|
case value_t::Table : {return parse_inline_table(loc); }
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
const auto msg = format_underline("[error] toml::parse_value: "
|
||||||
|
"unknown token appeared", {{std::addressof(loc), "unknown"}});
|
||||||
|
loc.reset(first);
|
||||||
|
return err(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -1468,7 +1551,8 @@ parse_table_key(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return err(token.unwrap_err());
|
return err(format_underline("[error] toml::parse_table_key: "
|
||||||
|
"not a valid table key", {{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1476,7 +1560,7 @@ template<typename Container>
|
|||||||
result<std::pair<std::vector<key>, region<Container>>, std::string>
|
result<std::pair<std::vector<key>, region<Container>>, std::string>
|
||||||
parse_array_table_key(location<Container>& loc)
|
parse_array_table_key(location<Container>& loc)
|
||||||
{
|
{
|
||||||
if(auto token = lex_array_table::invoke(loc))
|
if(auto token = lex_array_table::invoke(loc, true))
|
||||||
{
|
{
|
||||||
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||||
|
|
||||||
@@ -1521,7 +1605,8 @@ parse_array_table_key(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return err(token.unwrap_err());
|
return err(format_underline("[error] toml::parse_array_table_key: "
|
||||||
|
"not a valid table key", {{std::addressof(loc), "here"}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1547,12 +1632,12 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
|||||||
const auto before = loc.iter();
|
const auto before = loc.iter();
|
||||||
if(const auto tmp = parse_array_table_key(loc)) // next table found
|
if(const auto tmp = parse_array_table_key(loc)) // next table found
|
||||||
{
|
{
|
||||||
loc.iter() = before;
|
loc.reset(before);
|
||||||
return ok(tab);
|
return ok(tab);
|
||||||
}
|
}
|
||||||
if(const auto tmp = parse_table_key(loc)) // next table found
|
if(const auto tmp = parse_table_key(loc)) // next table found
|
||||||
{
|
{
|
||||||
loc.iter() = before;
|
loc.reset(before);
|
||||||
return ok(tab);
|
return ok(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1592,7 +1677,7 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
|||||||
const auto msg = format_underline("[error] toml::parse_table: "
|
const auto msg = format_underline("[error] toml::parse_table: "
|
||||||
"invalid line format", {{std::addressof(loc), concat_to_string(
|
"invalid line format", {{std::addressof(loc), concat_to_string(
|
||||||
"expected newline, but got '", show_char(*loc.iter()), "'.")}});
|
"expected newline, but got '", show_char(*loc.iter()), "'.")}});
|
||||||
loc.iter() = before;
|
loc.reset(before);
|
||||||
return err(msg);
|
return err(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1695,7 +1780,7 @@ inline table parse(std::istream& is, std::string fname = "unknown file")
|
|||||||
std::memcpy(BOM.data(), loc.source()->data(), 3);
|
std::memcpy(BOM.data(), loc.source()->data(), 3);
|
||||||
if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
|
if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
|
||||||
{
|
{
|
||||||
loc.iter() += 3; // BOM found. skip.
|
loc.advance(3); // BOM found. skip.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_REGION_H
|
#ifndef TOML11_REGION_HPP
|
||||||
#define TOML11_REGION_H
|
#define TOML11_REGION_HPP
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -15,7 +15,7 @@ namespace toml
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
// helper function to avoid std::string(0, 'c')
|
// helper function to avoid std::string(0, 'c') or std::string(iter, iter)
|
||||||
template<typename Iterator>
|
template<typename Iterator>
|
||||||
std::string make_string(Iterator first, Iterator last)
|
std::string make_string(Iterator first, Iterator last)
|
||||||
{
|
{
|
||||||
@@ -28,9 +28,7 @@ inline std::string make_string(std::size_t len, char c)
|
|||||||
return std::string(len, c);
|
return std::string(len, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// region in a container, normally in a file content.
|
// region_base is a base class of location and region that are defined below.
|
||||||
// shared_ptr points the resource that the iter points.
|
|
||||||
// combinators returns this.
|
|
||||||
// it will be used to generate better error messages.
|
// it will be used to generate better error messages.
|
||||||
struct region_base
|
struct region_base
|
||||||
{
|
{
|
||||||
@@ -48,25 +46,32 @@ struct region_base
|
|||||||
virtual std::string line() const {return std::string("unknown line");}
|
virtual std::string line() const {return std::string("unknown line");}
|
||||||
virtual std::string line_num() const {return std::string("?");}
|
virtual std::string line_num() const {return std::string("?");}
|
||||||
|
|
||||||
virtual std::size_t before() const noexcept {return 0;}
|
// length of the region
|
||||||
virtual std::size_t size() const noexcept {return 0;}
|
virtual std::size_t size() const noexcept {return 0;}
|
||||||
|
// number of characters in the line before the region
|
||||||
|
virtual std::size_t before() const noexcept {return 0;}
|
||||||
|
// number of characters in the line after the region
|
||||||
virtual std::size_t after() const noexcept {return 0;}
|
virtual std::size_t after() const noexcept {return 0;}
|
||||||
};
|
};
|
||||||
|
|
||||||
// location in a container, normally in a file content.
|
// location represents a position in a container, which contains a file content.
|
||||||
// shared_ptr points the resource that the iter points.
|
|
||||||
// it can be used not only for resource handling, but also error message.
|
|
||||||
//
|
|
||||||
// it can be considered as a region that contains only one character.
|
// it can be considered as a region that contains only one character.
|
||||||
|
//
|
||||||
|
// it contains pointer to the file content and iterator that points the current
|
||||||
|
// location.
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
struct location final : public region_base
|
struct location final : public region_base
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
|
||||||
using const_iterator = typename Container::const_iterator;
|
using const_iterator = typename Container::const_iterator;
|
||||||
using source_ptr = std::shared_ptr<const Container>;
|
using source_ptr = std::shared_ptr<const Container>;
|
||||||
|
|
||||||
|
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
||||||
|
static_assert(std::is_same<std::random_access_iterator_tag,
|
||||||
|
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
||||||
|
"container should be randomly accessible");
|
||||||
|
|
||||||
location(std::string name, Container cont)
|
location(std::string name, Container cont)
|
||||||
: source_(std::make_shared<Container>(std::move(cont))),
|
: source_(std::make_shared<Container>(std::move(cont))), line_number_(1),
|
||||||
source_name_(std::move(name)), iter_(source_->cbegin())
|
source_name_(std::move(name)), iter_(source_->cbegin())
|
||||||
{}
|
{}
|
||||||
location(const location&) = default;
|
location(const location&) = default;
|
||||||
@@ -77,18 +82,54 @@ struct location final : public region_base
|
|||||||
|
|
||||||
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
|
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
|
||||||
|
|
||||||
const_iterator& iter() noexcept {return iter_;}
|
// this const prohibits codes like `++(loc.iter())`.
|
||||||
const_iterator iter() const noexcept {return iter_;}
|
const const_iterator iter() const noexcept {return iter_;}
|
||||||
|
|
||||||
const_iterator begin() const noexcept {return source_->cbegin();}
|
const_iterator begin() const noexcept {return source_->cbegin();}
|
||||||
const_iterator end() const noexcept {return source_->cend();}
|
const_iterator end() const noexcept {return source_->cend();}
|
||||||
|
|
||||||
|
// XXX `location::line_num()` used to be implemented using `std::count` to
|
||||||
|
// count a number of '\n'. But with a long toml file (typically, 10k lines),
|
||||||
|
// it becomes intolerably slow because each time it generates error messages,
|
||||||
|
// it counts '\n' from thousands of characters. To workaround it, I decided
|
||||||
|
// to introduce `location::line_number_` member variable and synchronize it
|
||||||
|
// to the location changes the point to look. So an overload of `iter()`
|
||||||
|
// which returns mutable reference is removed and `advance()`, `retrace()`
|
||||||
|
// and `reset()` is added.
|
||||||
|
void advance(std::size_t n = 1) noexcept
|
||||||
|
{
|
||||||
|
this->line_number_ += std::count(this->iter_, this->iter_ + n, '\n');
|
||||||
|
this->iter_ += n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void retrace(std::size_t n = 1) noexcept
|
||||||
|
{
|
||||||
|
this->line_number_ -= std::count(this->iter_ - n, this->iter_, '\n');
|
||||||
|
this->iter_ -= n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void reset(const_iterator rollback) noexcept
|
||||||
|
{
|
||||||
|
// since c++11, std::distance works in both ways for random-access
|
||||||
|
// iterators and returns a negative value if `first > last`.
|
||||||
|
if(0 <= std::distance(rollback, this->iter_)) // rollback < iter
|
||||||
|
{
|
||||||
|
this->line_number_ -= std::count(rollback, this->iter_, '\n');
|
||||||
|
}
|
||||||
|
else // iter < rollback [[unlikely]]
|
||||||
|
{
|
||||||
|
this->line_number_ += std::count(this->iter_, rollback, '\n');
|
||||||
|
}
|
||||||
|
this->iter_ = rollback;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string str() const override {return make_string(1, *this->iter());}
|
std::string str() const override {return make_string(1, *this->iter());}
|
||||||
std::string name() const override {return source_name_;}
|
std::string name() const override {return source_name_;}
|
||||||
|
|
||||||
std::string line_num() const override
|
std::string line_num() const override
|
||||||
{
|
{
|
||||||
return std::to_string(1+std::count(this->begin(), this->iter(), '\n'));
|
return std::to_string(this->line_number_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string line() const override
|
std::string line() const override
|
||||||
@@ -127,17 +168,26 @@ struct location final : public region_base
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
source_ptr source_;
|
source_ptr source_;
|
||||||
|
std::size_t line_number_;
|
||||||
std::string source_name_;
|
std::string source_name_;
|
||||||
const_iterator iter_;
|
const_iterator iter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// region represents a range in a container, which contains a file content.
|
||||||
|
//
|
||||||
|
// it contains pointer to the file content and iterator that points the first
|
||||||
|
// and last location.
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
struct region final : public region_base
|
struct region final : public region_base
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
|
||||||
using const_iterator = typename Container::const_iterator;
|
using const_iterator = typename Container::const_iterator;
|
||||||
using source_ptr = std::shared_ptr<const Container>;
|
using source_ptr = std::shared_ptr<const Container>;
|
||||||
|
|
||||||
|
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
||||||
|
static_assert(std::is_same<std::random_access_iterator_tag,
|
||||||
|
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
||||||
|
"container should be randomly accessible");
|
||||||
|
|
||||||
// delete default constructor. source_ never be null.
|
// delete default constructor. source_ never be null.
|
||||||
region() = delete;
|
region() = delete;
|
||||||
|
|
||||||
@@ -293,7 +343,8 @@ inline std::string format_underline(const std::string& message,
|
|||||||
{
|
{
|
||||||
// invalid
|
// invalid
|
||||||
// ~~~~~~~
|
// ~~~~~~~
|
||||||
retval << make_string(reg->size(), '~');
|
const auto underline_len = std::min(reg->size(), reg->line().size());
|
||||||
|
retval << make_string(underline_len, '~');
|
||||||
}
|
}
|
||||||
|
|
||||||
retval << ' ';
|
retval << ' ';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_RESULT_H
|
#ifndef TOML11_RESULT_HPP
|
||||||
#define TOML11_RESULT_H
|
#define TOML11_RESULT_HPP
|
||||||
#include "traits.hpp"
|
#include "traits.hpp"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|||||||
@@ -483,15 +483,19 @@ struct serializer
|
|||||||
|
|
||||||
inline std::string
|
inline std::string
|
||||||
format(const value& v, std::size_t w = 80,
|
format(const value& v, std::size_t w = 80,
|
||||||
int fprec = std::numeric_limits<toml::floating>::max_digits10)
|
int fprec = std::numeric_limits<toml::floating>::max_digits10,
|
||||||
|
bool force_inline = false)
|
||||||
{
|
{
|
||||||
return visit(serializer(w, fprec, true), v);
|
// if value is a table, it is considered to be a root object.
|
||||||
|
// the root object can't be an inline table. so pass false. otherwise, true.
|
||||||
|
return visit(serializer(w, fprec, (!v.is_table()) || force_inline), v);
|
||||||
}
|
}
|
||||||
inline std::string
|
inline std::string
|
||||||
format(const table& t, std::size_t w = 80,
|
format(const table& t, std::size_t w = 80,
|
||||||
int fprec = std::numeric_limits<toml::floating>::max_digits10)
|
int fprec = std::numeric_limits<toml::floating>::max_digits10,
|
||||||
|
bool force_inline = false)
|
||||||
{
|
{
|
||||||
return serializer(w, fprec, true)(t);
|
return serializer(w, fprec, force_inline)(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename charT, typename traits>
|
template<typename charT, typename traits>
|
||||||
@@ -506,6 +510,18 @@ operator<<(std::basic_ostream<charT, traits>& os, const value& v)
|
|||||||
os << visit(serializer(w, fprec, false), v);
|
os << visit(serializer(w, fprec, false), v);
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
template<typename charT, typename traits>
|
||||||
|
std::basic_ostream<charT, traits>&
|
||||||
|
operator<<(std::basic_ostream<charT, traits>& os, const table& v)
|
||||||
|
{
|
||||||
|
// get status of std::setw().
|
||||||
|
const std::size_t w = os.width();
|
||||||
|
const int fprec = os.precision();
|
||||||
|
os.width(0);
|
||||||
|
// the root object can't be an inline table. so pass `false`.
|
||||||
|
os << serializer(w, fprec, false)(v);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
} // toml
|
} // toml
|
||||||
#endif// TOML11_SERIALIZER_HPP
|
#endif// TOML11_SERIALIZER_HPP
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_STRING_H
|
#ifndef TOML11_STRING_HPP
|
||||||
#define TOML11_STRING_H
|
#define TOML11_STRING_HPP
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
// Copyright Toru Niina 2017.
|
|
||||||
// Distributed under the MIT License.
|
|
||||||
#ifndef TOML11_TO_TOML
|
|
||||||
#define TOML11_TO_TOML
|
|
||||||
#include "value.hpp"
|
|
||||||
|
|
||||||
namespace toml
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
TOML11_MARK_AS_DEPRECATED
|
|
||||||
inline value to_toml(T&& x)
|
|
||||||
{
|
|
||||||
return value(std::forward<T>(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
TOML11_MARK_AS_DEPRECATED
|
|
||||||
inline value to_toml(T&& x, string_t kind)
|
|
||||||
{
|
|
||||||
return value(std::forward<T>(x), kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
TOML11_MARK_AS_DEPRECATED
|
|
||||||
inline value to_toml(local_date d, local_time t)
|
|
||||||
{
|
|
||||||
return value(local_datetime(d, t));
|
|
||||||
}
|
|
||||||
TOML11_MARK_AS_DEPRECATED
|
|
||||||
inline value to_toml(local_date d, local_time t, time_offset ofs)
|
|
||||||
{
|
|
||||||
return value(offset_datetime(d, t, ofs));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ... Ts>
|
|
||||||
TOML11_MARK_AS_DEPRECATED
|
|
||||||
inline value to_toml(Ts&& ... xs)
|
|
||||||
{
|
|
||||||
return value(toml::array{toml::value(std::forward<Ts>(xs)) ... });
|
|
||||||
}
|
|
||||||
|
|
||||||
TOML11_MARK_AS_DEPRECATED
|
|
||||||
inline value to_toml(std::initializer_list<std::pair<std::string, toml::value>> xs)
|
|
||||||
{
|
|
||||||
return value(toml::table(xs.begin(), xs.end()));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // toml
|
|
||||||
#endif // TOML11_TO_TOML
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_TRAITS
|
#ifndef TOML11_TRAITS_HPP
|
||||||
#define TOML11_TRAITS
|
#define TOML11_TRAITS_HPP
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class value; // forward decl
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -45,6 +48,22 @@ struct has_resize_method_impl
|
|||||||
template<typename T> static std::false_type check(...);
|
template<typename T> static std::false_type check(...);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct has_from_toml_method_impl
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
static std::true_type check(
|
||||||
|
decltype(std::declval<T>().from_toml(std::declval<::toml::value>()))*);
|
||||||
|
template<typename T>
|
||||||
|
static std::false_type check(...);
|
||||||
|
};
|
||||||
|
struct has_into_toml_method_impl
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
static std::true_type check(decltype(std::declval<T>().into_toml())*);
|
||||||
|
template<typename T>
|
||||||
|
static std::false_type check(...);
|
||||||
|
};
|
||||||
|
|
||||||
/// Intel C++ compiler can not use decltype in parent class declaration, here
|
/// Intel C++ compiler can not use decltype in parent class declaration, here
|
||||||
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
|
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
|
||||||
#ifdef __INTEL_COMPILER
|
#ifdef __INTEL_COMPILER
|
||||||
@@ -62,6 +81,14 @@ struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
|
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct has_from_toml_method
|
||||||
|
: decltype(has_from_toml_method_impl::check<T>(nullptr)){};
|
||||||
|
template<typename T>
|
||||||
|
struct has_into_toml_method
|
||||||
|
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
||||||
|
|
||||||
#ifdef __INTEL_COMPILER
|
#ifdef __INTEL_COMPILER
|
||||||
#undef decltype(...)
|
#undef decltype(...)
|
||||||
#endif
|
#endif
|
||||||
@@ -142,6 +169,21 @@ using return_type_of_t = typename std::result_of<F(Args...)>::type;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// is_string_literal
|
||||||
|
//
|
||||||
|
// to use this, pass `typename remove_reference<T>::type` to T.
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_string_literal:
|
||||||
|
disjunction<
|
||||||
|
std::is_same<const char*, T>,
|
||||||
|
conjunction<
|
||||||
|
std::is_array<T>,
|
||||||
|
std::is_same<const char, typename std::remove_extent<T>::type>
|
||||||
|
>
|
||||||
|
>{};
|
||||||
|
|
||||||
}// detail
|
}// detail
|
||||||
}//toml
|
}//toml
|
||||||
#endif // TOML_TRAITS
|
#endif // TOML_TRAITS
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_TYPES_H
|
#ifndef TOML11_TYPES_HPP
|
||||||
#define TOML11_TYPES_H
|
#define TOML11_TYPES_HPP
|
||||||
#include "datetime.hpp"
|
#include "datetime.hpp"
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
#include "traits.hpp"
|
#include "traits.hpp"
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_UTILITY
|
#ifndef TOML11_UTILITY_HPP
|
||||||
#define TOML11_UTILITY
|
#define TOML11_UTILITY_HPP
|
||||||
#include "traits.hpp"
|
#include "traits.hpp"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#if __cplusplus >= 201402L
|
#if __cplusplus >= 201402L
|
||||||
# define TOML11_MARK_AS_DEPRECATED [[deprecated]]
|
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
# define TOML11_MARK_AS_DEPRECATED __attribute__((deprecated))
|
# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
# define TOML11_MARK_AS_DEPRECATED __declspec(deprecated)
|
# define TOML11_MARK_AS_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||||
#else
|
#else
|
||||||
# define TOML11_MARK_AS_DEPRECATED
|
# define TOML11_MARK_AS_DEPRECATED
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
127
toml/value.hpp
127
toml/value.hpp
@@ -1,8 +1,9 @@
|
|||||||
// Copyright Toru Niina 2017.
|
// Copyright Toru Niina 2017.
|
||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_VALUE
|
#ifndef TOML11_VALUE_HPP
|
||||||
#define TOML11_VALUE
|
#define TOML11_VALUE_HPP
|
||||||
#include "traits.hpp"
|
#include "traits.hpp"
|
||||||
|
#include "into.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "storage.hpp"
|
#include "storage.hpp"
|
||||||
@@ -473,7 +474,7 @@ class value
|
|||||||
region_info_(std::make_shared<region_base>(region_base{}))
|
region_info_(std::make_shared<region_base>(region_base{}))
|
||||||
{
|
{
|
||||||
array ary; ary.reserve(list.size());
|
array ary; ary.reserve(list.size());
|
||||||
for(auto& elem : list) {ary.emplace_back(std::move(elem));}
|
for(const auto& elem : list) {ary.emplace_back(elem);}
|
||||||
assigner(this->array_, std::move(ary));
|
assigner(this->array_, std::move(ary));
|
||||||
}
|
}
|
||||||
template<typename T, typename std::enable_if<detail::is_container<T>::value,
|
template<typename T, typename std::enable_if<detail::is_container<T>::value,
|
||||||
@@ -485,7 +486,7 @@ class value
|
|||||||
this->region_info_ = std::make_shared<region_base>(region_base{});
|
this->region_info_ = std::make_shared<region_base>(region_base{});
|
||||||
|
|
||||||
array ary; ary.reserve(list.size());
|
array ary; ary.reserve(list.size());
|
||||||
for(auto& elem : list) {ary.emplace_back(std::move(elem));}
|
for(const auto& elem : list) {ary.emplace_back(elem);}
|
||||||
assigner(this->array_, std::move(ary));
|
assigner(this->array_, std::move(ary));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -533,10 +534,70 @@ class value
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// user-defined =========================================================
|
||||||
|
|
||||||
|
// convert using into_toml() method -------------------------------------
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||||
|
detail::has_into_toml_method<T> // but has `into_toml` method
|
||||||
|
>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
value(const T& ud): value(ud.into_toml()) {}
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<detail::conjunction<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||||
|
detail::has_into_toml_method<T> // but has `into_toml` method
|
||||||
|
>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
value& operator=(const T& ud)
|
||||||
|
{
|
||||||
|
*this = ud.into_toml();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert using into<T> struct -----------------------------------------
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>::value,
|
||||||
|
std::nullptr_t>::type = nullptr,
|
||||||
|
std::size_t S = sizeof(::toml::into<T>)>
|
||||||
|
value(const T& ud): value(::toml::into<T>::into_toml(ud)) {}
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<
|
||||||
|
detail::negation<detail::is_exact_toml_type<T>>::value,
|
||||||
|
std::nullptr_t>::type = nullptr,
|
||||||
|
std::size_t S = sizeof(::toml::into<T>)>
|
||||||
|
value& operator=(const T& ud)
|
||||||
|
{
|
||||||
|
*this = ::toml::into<T>::into_toml(ud);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for internal use ------------------------------------------------------
|
||||||
|
|
||||||
|
template<typename T, typename Container, typename std::enable_if<
|
||||||
|
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
|
||||||
|
value(std::pair<T, detail::region<Container>> parse_result)
|
||||||
|
: value(std::move(parse_result.first), std::move(parse_result.second))
|
||||||
|
{}
|
||||||
|
|
||||||
|
// type checking and casting ============================================
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool is() const noexcept {return value_traits<T>::type_index == this->type_;}
|
bool is() const noexcept {return value_traits<T>::type_index == this->type_;}
|
||||||
bool is(value_t t) const noexcept {return t == this->type_;}
|
bool is(value_t t) const noexcept {return t == this->type_;}
|
||||||
|
|
||||||
|
bool is_uninitialized() const noexcept {return this->is(value_t::Empty );}
|
||||||
|
bool is_boolean() const noexcept {return this->is(value_t::Boolean );}
|
||||||
|
bool is_integer() const noexcept {return this->is(value_t::Integer );}
|
||||||
|
bool is_float() const noexcept {return this->is(value_t::Float );}
|
||||||
|
bool is_string() const noexcept {return this->is(value_t::String );}
|
||||||
|
bool is_offset_datetime() const noexcept {return this->is(value_t::OffsetDatetime);}
|
||||||
|
bool is_local_datetime() const noexcept {return this->is(value_t::LocalDatetime );}
|
||||||
|
bool is_local_date() const noexcept {return this->is(value_t::LocalDate );}
|
||||||
|
bool is_local_time() const noexcept {return this->is(value_t::LocalTime );}
|
||||||
|
bool is_array() const noexcept {return this->is(value_t::Array );}
|
||||||
|
bool is_table() const noexcept {return this->is(value_t::Table );}
|
||||||
|
|
||||||
value_t type() const {return type_;}
|
value_t type() const {return type_;}
|
||||||
|
|
||||||
template<value_t T>
|
template<value_t T>
|
||||||
@@ -794,38 +855,40 @@ inline bool operator>=(const toml::value& lhs, const toml::value& rhs)
|
|||||||
return !(lhs < rhs);
|
return !(lhs < rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
inline std::string format_error(const std::string& err_msg,
|
||||||
{
|
|
||||||
inline std::string format_error_impl(const std::string& err_msg,
|
|
||||||
std::vector<std::pair<region_base const*, std::string>> val,
|
|
||||||
std::vector<std::string> hints)
|
|
||||||
{
|
|
||||||
return format_underline(err_msg, std::move(val), std::move(hints));
|
|
||||||
}
|
|
||||||
inline std::string format_error_impl(const std::string& err_msg,
|
|
||||||
std::vector<std::pair<region_base const*, std::string>> val)
|
|
||||||
{
|
|
||||||
return format_underline(err_msg, std::move(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ... Ts>
|
|
||||||
std::string format_error_impl(const std::string& err_msg,
|
|
||||||
std::vector<std::pair<region_base const*, std::string>> val,
|
|
||||||
const toml::value& v, const std::string& comment,
|
const toml::value& v, const std::string& comment,
|
||||||
Ts&& ... args)
|
std::vector<std::string> hints = {})
|
||||||
{
|
{
|
||||||
val.push_back(std::make_pair(std::addressof(get_region(v)), comment));
|
return detail::format_underline(err_msg,
|
||||||
return format_error_impl(err_msg, std::move(val), std::forward<Ts>(args)...);
|
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||||
|
{std::addressof(detail::get_region(v)), comment}
|
||||||
|
}, std::move(hints));
|
||||||
}
|
}
|
||||||
} // detail
|
|
||||||
|
|
||||||
template<typename ... Ts>
|
inline std::string format_error(const std::string& err_msg,
|
||||||
std::string format_error(const std::string& err_msg, Ts&& ... args)
|
const toml::value& v1, const std::string& comment1,
|
||||||
|
const toml::value& v2, const std::string& comment2,
|
||||||
|
std::vector<std::string> hints = {})
|
||||||
{
|
{
|
||||||
std::vector<std::pair<detail::region_base const*, std::string>> val;
|
return detail::format_underline(err_msg,
|
||||||
val.reserve(sizeof...(args) / 2);
|
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||||
return detail::format_error_impl(err_msg, std::move(val),
|
{std::addressof(detail::get_region(v1)), comment1},
|
||||||
std::forward<Ts>(args)...);
|
{std::addressof(detail::get_region(v2)), comment2}
|
||||||
|
}, std::move(hints));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string format_error(const std::string& err_msg,
|
||||||
|
const toml::value& v1, const std::string& comment1,
|
||||||
|
const toml::value& v2, const std::string& comment2,
|
||||||
|
const toml::value& v3, const std::string& comment3,
|
||||||
|
std::vector<std::string> hints = {})
|
||||||
|
{
|
||||||
|
return detail::format_underline(err_msg,
|
||||||
|
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||||
|
{std::addressof(detail::get_region(v1)), comment1},
|
||||||
|
{std::addressof(detail::get_region(v2)), comment2},
|
||||||
|
{std::addressof(detail::get_region(v3)), comment3}
|
||||||
|
}, std::move(hints));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
@@ -877,7 +940,7 @@ visit(Visitor&& visitor, toml::value& v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
detail::return_type_of_t<Visitor, toml::boolean&>
|
detail::return_type_of_t<Visitor, toml::boolean&&>
|
||||||
visit(Visitor&& visitor, toml::value&& v)
|
visit(Visitor&& visitor, toml::value&& v)
|
||||||
{
|
{
|
||||||
switch(v.type())
|
switch(v.type())
|
||||||
|
|||||||
Reference in New Issue
Block a user