mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
89 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bf9e42835 | ||
|
|
4a2c823d56 | ||
|
|
24c28c7f4f | ||
|
|
cab3144507 | ||
|
|
dee32e7d5e | ||
|
|
53a185e7a9 | ||
|
|
fd980a8c5d | ||
|
|
73ac43d70c | ||
|
|
adcd75e017 | ||
|
|
569341a514 | ||
|
|
0357d8fb57 | ||
|
|
00d40140ac | ||
|
|
1bfe8f1f54 | ||
|
|
bc143263cd | ||
|
|
1b19d5f1eb | ||
|
|
fd7da05798 | ||
|
|
cbaaaaca7c | ||
|
|
cf1c9371b6 | ||
|
|
62e8d58d8d | ||
|
|
acbc2a73cb | ||
|
|
b2daf916b3 | ||
|
|
e66bb3d359 | ||
|
|
cfaa94f072 | ||
|
|
2f4f3efbf0 | ||
|
|
06ae67502a | ||
|
|
57cb806e14 | ||
|
|
d6f3654185 | ||
|
|
8befe3f1ad | ||
|
|
2d43119ac7 | ||
|
|
436af12815 | ||
|
|
4f4d4380f2 | ||
|
|
31debcb8aa | ||
|
|
2afa0ff0c3 | ||
|
|
46047c48bf | ||
|
|
897aecf5d4 | ||
|
|
7db8388d17 | ||
|
|
62c993e096 | ||
|
|
014d882f8f | ||
|
|
2cbb93d86e | ||
|
|
a19b94511b | ||
|
|
70d0049511 | ||
|
|
717f5929c2 | ||
|
|
81abb6c9d7 | ||
|
|
8bba3c8a14 | ||
|
|
b13e727b90 | ||
|
|
d352c9e66f | ||
|
|
c0aaba06d0 | ||
|
|
1633268d57 | ||
|
|
3bf1c2b820 | ||
|
|
4dbd2cb9fe | ||
|
|
65124a8d2e | ||
|
|
1b78f161f5 | ||
|
|
0ce259ada0 | ||
|
|
74da49f87f | ||
|
|
d5d697639c | ||
|
|
0b365ca7d3 | ||
|
|
db6f3d5d11 | ||
|
|
87be890e07 | ||
|
|
d72dc706d0 | ||
|
|
4cbbcd8f62 | ||
|
|
a2631ecacb | ||
|
|
4bcc5e8375 | ||
|
|
90f84000ba | ||
|
|
20a13754a7 | ||
|
|
aa7b9a3965 | ||
|
|
84ac1d10f3 | ||
|
|
0d623856a7 | ||
|
|
ec0d4e4e8c | ||
|
|
80ea736b3f | ||
|
|
ebaa5dfb51 | ||
|
|
f3bdf083fe | ||
|
|
1ce54a9cf9 | ||
|
|
6383a93ce7 | ||
|
|
01aa2ef5b2 | ||
|
|
819351f5a4 | ||
|
|
2967cebfb3 | ||
|
|
32e9a2c1c7 | ||
|
|
8e0a40a1aa | ||
|
|
e460826084 | ||
|
|
aa3445f38c | ||
|
|
408b7bf35e | ||
|
|
6185dfee14 | ||
|
|
37aa2739a5 | ||
|
|
d061c33a16 | ||
|
|
0c7d2d07d4 | ||
|
|
62cf4373bd | ||
|
|
a74ad23514 | ||
|
|
2d9b4992ec | ||
|
|
82e8c1e68b |
57
.travis.yml
57
.travis.yml
@@ -5,7 +5,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-5"
|
||||
env: COMPILER="g++-5" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -16,7 +16,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-6"
|
||||
env: COMPILER="g++-6" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -27,7 +27,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-7"
|
||||
env: COMPILER="g++-7" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -38,7 +38,18 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-8"
|
||||
env: COMPILER="g++-8" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-8
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-8" CXX_STANDARD=17
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -49,7 +60,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-3.7"
|
||||
env: COMPILER="clang++-3.7" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -61,7 +72,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-4.0"
|
||||
env: COMPILER="clang++-4.0" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -73,7 +84,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-5.0"
|
||||
env: COMPILER="clang++-5.0" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -85,7 +96,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-6.0"
|
||||
env: COMPILER="clang++-6.0" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -97,7 +108,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-7"
|
||||
env: COMPILER="clang++-7" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -109,7 +120,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-8"
|
||||
env: COMPILER="clang++-8" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -118,14 +129,38 @@ matrix:
|
||||
packages:
|
||||
- clang-8
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-8" CXX_STANDARD=17
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- clang-8
|
||||
- g++-8
|
||||
- libboost-all-dev
|
||||
- os: osx
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: CXX_STANDARD=11
|
||||
|
||||
script:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
mkdir -p cmake
|
||||
travis_retry wget "https://cmake.org/files/v3.11/cmake-3.11.2-Linux-x86_64.tar.gz"
|
||||
tar xf cmake-3.11.2-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
||||
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
||||
else
|
||||
brew upgrade cmake
|
||||
fi
|
||||
- cmake --version
|
||||
- mkdir build
|
||||
- cd build
|
||||
- git clone https://github.com/toml-lang/toml.git
|
||||
- cmake -DCMAKE_CXX_COMPILER=$COMPILER ..
|
||||
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD ..
|
||||
- make
|
||||
- ctest --output-on-failure
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
enable_testing()
|
||||
|
||||
project(toml11)
|
||||
|
||||
set(toml11_VERSION_MAYOR 2)
|
||||
set(toml11_VERSION_MINOR 4)
|
||||
set(toml11_VERSION_PATCH 0)
|
||||
set(toml11_VERSION
|
||||
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
||||
)
|
||||
|
||||
option(toml11_BUILD_TEST "Build toml tests" ON)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
set(CXX_STANDARD_REQUIRED ON)
|
||||
else()
|
||||
# Manually check for C++11 compiler flag.
|
||||
@@ -31,5 +44,62 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
add_subdirectory(tests)
|
||||
# Set some common directories
|
||||
include(GNUInstallDirs)
|
||||
set(toml11_install_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/toml11)
|
||||
set(toml11_install_include_dir ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
set(toml11_config_dir ${CMAKE_CURRENT_BINARY_DIR}/cmake/)
|
||||
set(toml11_config ${toml11_config_dir}/toml11Config.cmake)
|
||||
set(toml11_config_version ${toml11_config_dir}/toml11ConfigVersion.cmake)
|
||||
|
||||
add_library(toml11 INTERFACE)
|
||||
target_include_directories(toml11 INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${toml11_install_include_dir}>
|
||||
)
|
||||
add_library(toml11::toml11 ALIAS toml11)
|
||||
|
||||
# Write config and version config files
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
${toml11_config_version}
|
||||
VERSION ${toml11_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
cmake/toml11Config.cmake.in
|
||||
${toml11_config}
|
||||
INSTALL_DESTINATION ${toml11_install_cmake_dir}
|
||||
PATH_VARS toml11_install_cmake_dir
|
||||
)
|
||||
|
||||
# Install config files
|
||||
install(FILES ${toml11_config} ${toml11_config_version}
|
||||
DESTINATION ${toml11_install_cmake_dir}
|
||||
)
|
||||
|
||||
# Install header files
|
||||
install(
|
||||
FILES toml.hpp
|
||||
DESTINATION "${toml11_install_include_dir}"
|
||||
)
|
||||
install(
|
||||
DIRECTORY "toml"
|
||||
DESTINATION "${toml11_install_include_dir}"
|
||||
FILES_MATCHING PATTERN "*.hpp"
|
||||
)
|
||||
|
||||
# Export targets and install them
|
||||
install(TARGETS toml11
|
||||
EXPORT toml11Targets
|
||||
)
|
||||
install(EXPORT toml11Targets
|
||||
FILE toml11Targets.cmake
|
||||
DESTINATION ${toml11_install_cmake_dir}
|
||||
NAMESPACE toml11::
|
||||
)
|
||||
|
||||
if (toml11_BUILD_TEST)
|
||||
add_subdirectory(tests)
|
||||
endif ()
|
||||
|
||||
249
README.md
249
README.md
@@ -63,6 +63,7 @@ int main()
|
||||
- [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)
|
||||
- [Getting comments related to a value](#getting-comments)
|
||||
- [Serializing TOML data](#serializing-toml-data)
|
||||
- [Underlying types](#underlying-types)
|
||||
- [Running Tests](#running-tests)
|
||||
@@ -143,6 +144,24 @@ terminate called after throwing an instance of 'toml::syntax_error'
|
||||
| ~~~~~~~ table defined twice
|
||||
```
|
||||
|
||||
When toml11 encounters a malformed value, it tries to detect what type it is.
|
||||
Then it shows hints to fix the format. An error message while reading one of
|
||||
the malformed files in [the language agnostic test suite](https://github.com/BurntSushi/toml-test).
|
||||
is shown below.
|
||||
|
||||
```console
|
||||
what(): [error] bad time: should be HH:MM:SS.subsec
|
||||
--> ./datetime-malformed-no-secs.toml
|
||||
1 | no-secs = 1987-07-05T17:45Z
|
||||
| ^------- HH:MM:SS.subsec
|
||||
|
|
||||
Hint: pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999
|
||||
Hint: fail: 1979-05-27T7:32:00, 1979-05-27 17:32
|
||||
```
|
||||
|
||||
You can find other examples in a job named `output_result` on
|
||||
[CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||
|
||||
Since the error message generation is generally a difficult task, the current
|
||||
status is not ideal. If you encounter a weird error message, please let us know
|
||||
and contribute to improve the quality!
|
||||
@@ -187,6 +206,12 @@ See also [underlying types](#underlying-types).
|
||||
|
||||
NOTE: To enable to get a reference, conversions between Float and Integer are not supported.
|
||||
|
||||
After C++17, you can use `std::string_view` to get a string from a `toml::value`.
|
||||
|
||||
```cpp
|
||||
const auto sv = toml::get<std::string_view>(tab.at("key"));
|
||||
```
|
||||
|
||||
### In the case of type error
|
||||
|
||||
If you pass an invalid type to `toml::get`, `toml::type_error` will be thrown.
|
||||
@@ -418,6 +443,10 @@ toml::integer opt = 42;
|
||||
toml::integer& i = toml::get_or(v, opt); // this works.
|
||||
```
|
||||
|
||||
There is also a function `find_or`, but there is a known issue around overload
|
||||
resolution. To use it, passing a `toml::value`, not a `toml::table`, is strongly
|
||||
recommended.
|
||||
|
||||
## Expecting conversion
|
||||
|
||||
By using `toml::expect`, you will get your expected value or an error message
|
||||
@@ -444,36 +473,20 @@ const auto value = toml::expect<int>(data.at("number"))
|
||||
|
||||
## Finding a value from a 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
|
||||
it just searches an `unordered_map` and returns a value if it exists.
|
||||
toml11 provides a utility function to find a value from `toml::value` and `toml::table`.
|
||||
|
||||
```cpp
|
||||
const auto data = toml::parse("example.toml");
|
||||
const auto num = toml::find<int>(data, "num", /*for err msg*/"example.toml");
|
||||
const toml::value data = /* ... */;
|
||||
|
||||
// find a value named "num" from `data`.
|
||||
const auto num = toml::find<int>(data, "num");
|
||||
```
|
||||
|
||||
If the value does not exist, it throws `std::out_of_range` with an error message.
|
||||
When you pass a `toml::value`, `toml::find` first casts it to `toml::table`.
|
||||
If casting failed, `toml::type_error` will be thrown.
|
||||
|
||||
```console
|
||||
terminate called after throwing an instance of 'std::out_of_range'
|
||||
what(): [error] key "num" not found in example.toml
|
||||
```
|
||||
|
||||
You can use this with a `toml::value` that is expected to be a `toml::table`.
|
||||
It automatically casts the value to table.
|
||||
|
||||
```cpp
|
||||
const auto data = toml::parse("example.toml");
|
||||
const auto num = toml::find<int>(data.at("table"), "num");
|
||||
// expecting the following example.toml
|
||||
// [table]
|
||||
// num = 42
|
||||
```
|
||||
|
||||
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 an error message including table location.
|
||||
When the value does not exist, it throws `std::out_of_range` with an error message.
|
||||
By passing a `toml::value`, it shows an informative error message like the following.
|
||||
|
||||
```console
|
||||
terminate called after throwing an instance of 'std::out_of_range'
|
||||
@@ -483,46 +496,72 @@ terminate called after throwing an instance of 'std::out_of_range'
|
||||
| ~~~~~~~ in this table
|
||||
```
|
||||
|
||||
If it's not a `toml::table`, the same error as "invalid type" would be thrown.
|
||||
|
||||
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`.
|
||||
Contrary, since `toml::table` is just an alias of `std::unordered_map<toml::key, toml::value>`,
|
||||
you need to pass a name to the function to show the name in the exception with `toml::table`.
|
||||
|
||||
```cpp
|
||||
const auto data = toml::parse("example.toml");
|
||||
const auto num = toml::find_or(data.at("table"), "num", 42);
|
||||
const toml::table data = /* ... */;
|
||||
|
||||
// you need to pass the name of the table to show it in an error message
|
||||
const auto num = toml::find<int>(data, "num", "[data]");
|
||||
```
|
||||
|
||||
```console
|
||||
terminate called after throwing an instance of 'std::out_of_range'
|
||||
what(): [error] key "num" not found in [data]
|
||||
# table name is needed to show this part ^^^^^^
|
||||
```
|
||||
|
||||
By default (w/o template parameter), `toml::find` returns a `toml::value`.
|
||||
|
||||
```cpp
|
||||
const toml::value& subtable = toml::find(table, "subtable");
|
||||
```
|
||||
|
||||
__NOTE__:
|
||||
A new feature, recursive toml::find was planned to be introduced, but it was
|
||||
found that the change breaks a code that was previously compiled fine. So the
|
||||
change was reverted.
|
||||
The reason is that the overload resolution was ambiguous. To support this,
|
||||
in the next major update, overloads of `toml::find` for `toml::table` possibly
|
||||
be removed.
|
||||
|
||||
## 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)
|
||||
if(v.is_integer())
|
||||
{
|
||||
std::cout << "value is 42" << std::endl;
|
||||
std::cout << "value is an integer" << 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();
|
||||
namespace toml {
|
||||
class value {
|
||||
// ...
|
||||
bool is_boolean() const noexcept;
|
||||
bool is_integer() const noexcept;
|
||||
bool is_floating() const noexcept;
|
||||
bool is_string() const noexcept;
|
||||
bool is_offset_datetime() const noexcept;
|
||||
bool is_local_datetime() const noexcept;
|
||||
bool is_local_date() const noexcept;
|
||||
bool is_local_time() const noexcept;
|
||||
bool is_array() const noexcept;
|
||||
bool is_table() const noexcept;
|
||||
bool is_uninitialized() const noexcept;
|
||||
// ...
|
||||
};
|
||||
} // toml
|
||||
```
|
||||
|
||||
__NOTE__: `is_float` is marked as deprecated since v2.4.0 to make the function names consistent with snake case typenames. Please use `is_floating` instead.
|
||||
|
||||
Also, you can get `enum class` value from `toml::value`.
|
||||
|
||||
```cpp
|
||||
@@ -546,6 +585,69 @@ toml::value v = /* ... */;
|
||||
if(v.is(toml::value_t::Boolean)) // ...
|
||||
```
|
||||
|
||||
## Casting value
|
||||
|
||||
So far, `toml::get` is introduced, but if you don't need any type conversion,
|
||||
`as_*` is simpler to use.
|
||||
|
||||
```cpp
|
||||
toml::value v = /* ... */;
|
||||
if(v.is_integer() && v.as_integer() == 42)
|
||||
{
|
||||
std::cout << "value is 42" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
`as_*` functions internally checks the current contained type for safety and
|
||||
throws `toml::type_error` if the contained value type is different (after toml11
|
||||
v2.4.0). If you already confirmed that the value has the type you will cast
|
||||
into, you can skip the additional checking by passing `std::nothrow` object to it.
|
||||
|
||||
```cpp
|
||||
toml::value v = /* ... */;
|
||||
if(v.is_integer() && v.as_integer(std::nothrow) == 42) // never fail
|
||||
{
|
||||
std::cout << "value is 42" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
The full list of the functions is below.
|
||||
|
||||
```cpp
|
||||
namespace toml {
|
||||
class value {
|
||||
// ...
|
||||
const boolean& as_boolean() const&;
|
||||
const integer& as_integer() const&;
|
||||
const floating& as_floating() const&;
|
||||
const string& as_string() const&;
|
||||
const offset_datetime& as_offset_datetime() const&;
|
||||
const local_datetime& as_local_datetime() const&;
|
||||
const local_date& as_local_date() const&;
|
||||
const local_time& as_local_time() const&;
|
||||
const array& as_array() const&;
|
||||
const table& as_table() const&;
|
||||
// --------------------------------------------------------
|
||||
// non-const version
|
||||
boolean& as_boolean() &;
|
||||
// ditto...
|
||||
// --------------------------------------------------------
|
||||
// rvalue version
|
||||
boolean&& as_boolean() &&;
|
||||
// ditto...
|
||||
|
||||
// --------------------------------------------------------
|
||||
// noexcept versions ...
|
||||
const boolean& as_boolean(const std::nothrow_t&) const& noexcept;
|
||||
boolean& as_boolean(const std::nothrow_t&) & noexcept;
|
||||
boolean&& as_boolean(const std::nothrow_t&) && noexcept;
|
||||
// ditto...
|
||||
};
|
||||
} // toml
|
||||
```
|
||||
|
||||
__NOTE__: `as_float` is marked as deprecated since v2.4.0 to make the function names consistent with snake case typenames. Please use `as_floating` instead.
|
||||
|
||||
## Visiting a toml::value
|
||||
|
||||
toml11 provides `toml::visit` to apply a function to `toml::value` in the
|
||||
@@ -618,7 +720,7 @@ add a comma after the first element (like `[1,]`).
|
||||
"[[table]]"_toml; // This is a table that has an array of tables inside.
|
||||
|
||||
"[[1]]"_toml; // This literal is ambiguous.
|
||||
// Currently, it becomes a table taht has array of table "1".
|
||||
// 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.
|
||||
@@ -831,6 +933,53 @@ you will get an error message like this.
|
||||
| ~~ maximum number here
|
||||
```
|
||||
|
||||
## Getting comments
|
||||
|
||||
Since toml11 keeps a file data until all the values are destructed, you can
|
||||
also extract a comment related to a value by calling `toml::value::comment()`.
|
||||
|
||||
If there is a comment just after a value (within the same line), you can get
|
||||
the specific comment by `toml::value::comment_inline()`.
|
||||
|
||||
If there are comments just before a value (without any newline between them),
|
||||
you can get the comments by `toml::value::comment_before()`.
|
||||
|
||||
`toml::value::comment()` returns the results of both functions after
|
||||
concatenating them.
|
||||
|
||||
```toml
|
||||
a = 42 # comment for a.
|
||||
|
||||
# comment for b.
|
||||
# this is also a comment for b.
|
||||
b = "foo"
|
||||
|
||||
c = [ # comment for c.
|
||||
3.14, # this is not a comment for c, but for 3.14.
|
||||
] # this is also a comment for c.
|
||||
```
|
||||
|
||||
```cpp
|
||||
// "# comment for a."
|
||||
const std::string com1 = toml::find(data, "a").comment();
|
||||
|
||||
// "# comment for b."
|
||||
const std::string com2 = toml::find(data, "b").comment();
|
||||
|
||||
// "# comment for c.\n# this is also a comment for c."
|
||||
const std::string com3 = toml::find(data, "c").comment();
|
||||
|
||||
// "# this is not a comment for c, but for 3.14."
|
||||
const std::string com3 = toml::find<toml::array>(data, "c").front().comment();
|
||||
```
|
||||
|
||||
Note that once a data in a value is modified, the related file region
|
||||
information would be deleted. Thus after modifying a data, you cannot find any
|
||||
comments.
|
||||
|
||||
Also note that currently it does not support any way to set a comment to a value.
|
||||
And currently, serializer does not take comments into account.
|
||||
|
||||
## Serializing TOML data
|
||||
|
||||
toml11 (after v2.1.0) enables you to serialize data into toml format.
|
||||
@@ -984,6 +1133,12 @@ I appreciate the help of the contributors who introduced the great feature to th
|
||||
- Improved error messages for invaild keys to show the location where the parser fails
|
||||
- Petr Beneš (@wbenny)
|
||||
- Fixed warnings on MSVC
|
||||
- Ivan Shynkarenka (@chronoxor)
|
||||
- Fixed Visual Studio 2019 warnings
|
||||
- @khoitd1997
|
||||
- Fixed warnings while type conversion
|
||||
- @KerstinKeller
|
||||
- Added installation script to CMake
|
||||
|
||||
## Licensing terms
|
||||
|
||||
|
||||
2
cmake/toml11Config.cmake.in
Normal file
2
cmake/toml11Config.cmake.in
Normal file
@@ -0,0 +1,2 @@
|
||||
@PACKAGE_INIT@
|
||||
include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake")
|
||||
@@ -21,6 +21,7 @@ set(TEST_NAMES
|
||||
test_parse_key
|
||||
test_parse_table_key
|
||||
test_literals
|
||||
test_comments
|
||||
test_get
|
||||
test_get_related_func
|
||||
test_from_toml
|
||||
@@ -87,7 +88,7 @@ add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
|
||||
|
||||
foreach(TEST_NAME ${TEST_NAMES})
|
||||
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
|
||||
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
|
||||
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
|
||||
@@ -104,3 +105,4 @@ endforeach(TEST_NAME)
|
||||
add_executable(test_multiple_translation_unit
|
||||
test_multiple_translation_unit_1.cpp
|
||||
test_multiple_translation_unit_2.cpp)
|
||||
target_link_libraries(test_multiple_translation_unit toml11::toml11)
|
||||
|
||||
125
tests/test_comments.cpp
Normal file
125
tests/test_comments.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#define BOOST_TEST_MODULE "test_comments"
|
||||
#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>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_comment_before)
|
||||
{
|
||||
using namespace toml::literals::toml_literals;
|
||||
{
|
||||
const toml::value v = u8R"(
|
||||
# comment for a.
|
||||
a = 42
|
||||
# comment for b.
|
||||
b = "baz"
|
||||
)"_toml;
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), u8"# comment for a.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), u8"# comment for b.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), "");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), "");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8"# comment for a.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8"# comment for b.");
|
||||
}
|
||||
|
||||
{
|
||||
const toml::value v = u8R"(
|
||||
# comment for a.
|
||||
# another comment for a.
|
||||
a = 42
|
||||
# comment for b.
|
||||
# also comment for b.
|
||||
b = "baz"
|
||||
)"_toml;
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), u8R"(# comment for a.
|
||||
# another comment for a.)");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), u8R"(# comment for b.
|
||||
# also comment for b.)");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), u8"");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), u8"");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8R"(# comment for a.
|
||||
# another comment for a.)");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8R"(# comment for b.
|
||||
# also comment for b.)");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_comment_inline)
|
||||
{
|
||||
using namespace toml::literals::toml_literals;
|
||||
{
|
||||
const toml::value v = u8R"(
|
||||
a = 42 # comment for a.
|
||||
b = "baz" # comment for b.
|
||||
)"_toml;
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), "");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), "");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), u8"# comment for a.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), u8"# comment for b.");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8"# comment for a.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8"# comment for b.");
|
||||
}
|
||||
{
|
||||
const toml::value v = u8R"(
|
||||
a = [ # comment for a.
|
||||
42,
|
||||
] # this also.
|
||||
b = [ # comment for b.
|
||||
"bar",
|
||||
]
|
||||
c = [
|
||||
3.14, # this is not a comment for c, but 3.14.
|
||||
] # comment for c.
|
||||
)"_toml;
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), "");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), "");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "c").comment_before(), "");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), u8R"(# comment for a.
|
||||
# this also.)");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), u8"# comment for b.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "c").comment_inline(), u8"# comment for c.");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8R"(# comment for a.
|
||||
# this also.)");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8"# comment for b.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "c").comment(), u8"# comment for c.");
|
||||
|
||||
const auto& c0 = toml::find<toml::array>(v, "c").at(0);
|
||||
BOOST_CHECK_EQUAL(c0.comment(), u8"# this is not a comment for c, but 3.14.");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_comment_both)
|
||||
{
|
||||
using namespace toml::literals::toml_literals;
|
||||
{
|
||||
const toml::value v = u8R"(
|
||||
# comment for a.
|
||||
a = 42 # inline comment for a.
|
||||
# comment for b.
|
||||
b = "baz" # inline comment for b.
|
||||
)"_toml;
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), "# comment for a.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), "# comment for b.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), "# inline comment for a.");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), "# inline comment for b.");
|
||||
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8R"(# comment for a.
|
||||
# inline comment for a.)");
|
||||
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8R"(# comment for b.
|
||||
# inline comment for b.)");
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,9 @@
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <array>
|
||||
#if __cplusplus >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_get_exact)
|
||||
@@ -166,6 +169,17 @@ BOOST_AUTO_TEST_CASE(test_get_string_type)
|
||||
toml::get<std::string>(v) += "bar";
|
||||
BOOST_CHECK_EQUAL("foobar", toml::get<std::string>(v));
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
{
|
||||
toml::value v("foo", toml::string_t::basic);
|
||||
BOOST_CHECK_EQUAL("foo", toml::get<std::string_view>(v));
|
||||
}
|
||||
{
|
||||
toml::value v("foo", toml::string_t::literal);
|
||||
BOOST_CHECK_EQUAL("foo", toml::get<std::string_view>(v));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_get_toml_array)
|
||||
|
||||
@@ -18,7 +18,7 @@ do { \
|
||||
BOOST_CHECK_EQUAL(static_cast<std::size_t>(std::distance( \
|
||||
loc.begin(), loc.iter())), region.size()); \
|
||||
} else { \
|
||||
std::cerr << "lexer " << lxr::pattern() << " failed with input `"; \
|
||||
std::cerr << "lexer failed with input `"; \
|
||||
std::cerr << token << "`. expected `" << expected << "`\n"; \
|
||||
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
|
||||
} \
|
||||
|
||||
@@ -78,8 +78,8 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
||||
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(v1.is_floating());
|
||||
BOOST_CHECK(v2.is_floating());
|
||||
BOOST_CHECK_CLOSE(toml::get<double>(v1), 3.1415, 0.00001);
|
||||
BOOST_CHECK_CLOSE(toml::get<double>(v2), 6.02e23, 0.0001);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
{
|
||||
toml::value v1(true);
|
||||
@@ -25,6 +30,10 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
|
||||
BOOST_CHECK_EQUAL(v2.as_boolean(), false);
|
||||
BOOST_CHECK_EQUAL(v1.as_boolean(std::nothrow), true);
|
||||
BOOST_CHECK_EQUAL(v2.as_boolean(std::nothrow), false);
|
||||
|
||||
v1 = false;
|
||||
v2 = true;
|
||||
@@ -40,6 +49,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v1.as_boolean(), false);
|
||||
BOOST_CHECK_EQUAL(v2.as_boolean(), true);
|
||||
|
||||
toml::value v3(v1);
|
||||
toml::value v4(v2);
|
||||
@@ -57,6 +68,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v3.as_boolean(), false);
|
||||
BOOST_CHECK_EQUAL(v4.as_boolean(), true);
|
||||
|
||||
toml::value v5(std::move(v1));
|
||||
toml::value v6(std::move(v2));
|
||||
@@ -72,6 +85,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v5.as_boolean(), false);
|
||||
BOOST_CHECK_EQUAL(v6.as_boolean(), true);
|
||||
|
||||
v1 = 42;
|
||||
v2 = 3.14;
|
||||
@@ -83,10 +98,12 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
BOOST_CHECK(v1.is<toml::Integer>());
|
||||
BOOST_CHECK(v2.is<toml::Float>());
|
||||
BOOST_CHECK(v1.is_integer());
|
||||
BOOST_CHECK(v2.is_float());
|
||||
BOOST_CHECK(v2.is_floating());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 42);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 3.14);
|
||||
BOOST_CHECK_EQUAL(v1.as_integer(), 42);
|
||||
BOOST_CHECK_EQUAL(v2.as_floating(), 3.14);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
@@ -105,6 +122,10 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
|
||||
BOOST_CHECK_EQUAL(v1.as_integer(), -42);
|
||||
BOOST_CHECK_EQUAL(v2.as_integer(), 42u);
|
||||
BOOST_CHECK_EQUAL(v1.as_integer(std::nothrow), -42);
|
||||
BOOST_CHECK_EQUAL(v2.as_integer(std::nothrow), 42u);
|
||||
|
||||
v1 = 54;
|
||||
v2 = -54;
|
||||
@@ -120,6 +141,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), -54);
|
||||
BOOST_CHECK_EQUAL(v1.as_integer(), 54);
|
||||
BOOST_CHECK_EQUAL(v2.as_integer(), -54);
|
||||
|
||||
toml::value v3(v1);
|
||||
toml::value v4(v2);
|
||||
@@ -137,6 +160,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Integer>(), -54);
|
||||
BOOST_CHECK_EQUAL(v3.as_integer(), 54);
|
||||
BOOST_CHECK_EQUAL(v4.as_integer(), -54);
|
||||
|
||||
toml::value v5(std::move(v1));
|
||||
toml::value v6(std::move(v2));
|
||||
@@ -152,6 +177,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Integer>(), -54);
|
||||
BOOST_CHECK_EQUAL(v5.as_integer(), 54);
|
||||
BOOST_CHECK_EQUAL(v6.as_integer(), -54);
|
||||
|
||||
v1 = true;
|
||||
v2 = false;
|
||||
@@ -167,6 +194,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
|
||||
BOOST_CHECK_EQUAL(v2.as_boolean(), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
@@ -180,11 +209,15 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v1.is<toml::Float>());
|
||||
BOOST_CHECK(v2.is<toml::Float>());
|
||||
BOOST_CHECK(v1.is_float());
|
||||
BOOST_CHECK(v2.is_float());
|
||||
BOOST_CHECK(v1.is_floating());
|
||||
BOOST_CHECK(v2.is_floating());
|
||||
|
||||
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_EQUAL (v1.as_floating(), 3.14);
|
||||
BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(), 3.14, 1e-2);
|
||||
BOOST_CHECK_EQUAL (v1.as_floating(std::nothrow), 3.14);
|
||||
BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(std::nothrow), 3.14, 1e-2);
|
||||
|
||||
v1 = 2.718f;
|
||||
v2 = 2.718;
|
||||
@@ -195,11 +228,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v1.is<toml::Float>());
|
||||
BOOST_CHECK(v2.is<toml::Float>());
|
||||
BOOST_CHECK(v1.is_float());
|
||||
BOOST_CHECK(v2.is_float());
|
||||
BOOST_CHECK(v1.is_floating());
|
||||
BOOST_CHECK(v2.is_floating());
|
||||
|
||||
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);
|
||||
BOOST_CHECK_CLOSE_FRACTION(v1.as_floating(), 2.718, 1e-3);
|
||||
BOOST_CHECK_EQUAL (v2.as_floating(), 2.718);
|
||||
|
||||
toml::value v3(v1);
|
||||
toml::value v4(v2);
|
||||
@@ -212,11 +247,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v4.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v3.is<toml::Float>());
|
||||
BOOST_CHECK(v4.is<toml::Float>());
|
||||
BOOST_CHECK(v3.is_float());
|
||||
BOOST_CHECK(v4.is_float());
|
||||
BOOST_CHECK(v3.is_floating());
|
||||
BOOST_CHECK(v4.is_floating());
|
||||
|
||||
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);
|
||||
BOOST_CHECK_CLOSE_FRACTION(v3.as_floating(), 2.718, 1e-3);
|
||||
BOOST_CHECK_EQUAL (v4.as_floating(), 2.718);
|
||||
|
||||
toml::value v5(std::move(v1));
|
||||
toml::value v6(std::move(v2));
|
||||
@@ -227,11 +264,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v6.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v5.is<toml::Float>());
|
||||
BOOST_CHECK(v6.is<toml::Float>());
|
||||
BOOST_CHECK(v5.is_float());
|
||||
BOOST_CHECK(v6.is_float());
|
||||
BOOST_CHECK(v5.is_floating());
|
||||
BOOST_CHECK(v6.is_floating());
|
||||
|
||||
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);
|
||||
BOOST_CHECK_CLOSE_FRACTION(v5.as_floating(), 2.718, 1e-3);
|
||||
BOOST_CHECK_EQUAL (v6.as_floating(), 2.718);
|
||||
|
||||
v1 = true;
|
||||
v2 = false;
|
||||
@@ -247,6 +286,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
|
||||
BOOST_CHECK_EQUAL(v2.as_boolean(), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
@@ -271,6 +312,12 @@ BOOST_AUTO_TEST_CASE(test_value_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_CHECK_EQUAL(v1.as_string(), "foo");
|
||||
BOOST_CHECK_EQUAL(v2.as_string(), "foo");
|
||||
BOOST_CHECK_EQUAL(v3.as_string(), "foo");
|
||||
BOOST_CHECK_EQUAL(v1.as_string(std::nothrow), "foo");
|
||||
BOOST_CHECK_EQUAL(v2.as_string(std::nothrow), "foo");
|
||||
BOOST_CHECK_EQUAL(v3.as_string(std::nothrow), "foo");
|
||||
|
||||
v1 = "bar";
|
||||
v2 = "bar";
|
||||
@@ -289,6 +336,10 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v1.as_string(), "bar");
|
||||
BOOST_CHECK_EQUAL(v2.as_string(), "bar");
|
||||
BOOST_CHECK_EQUAL(v3.as_string(), "bar");
|
||||
|
||||
|
||||
toml::value v4(v1);
|
||||
toml::value v5(v2);
|
||||
@@ -313,6 +364,10 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v4.as_string(), "bar");
|
||||
BOOST_CHECK_EQUAL(v5.as_string(), "bar");
|
||||
BOOST_CHECK_EQUAL(v6.as_string(), "bar");
|
||||
|
||||
|
||||
v4.cast<toml::value_t::String>().str.at(2) = 'z';
|
||||
v5.cast<toml::value_t::String>().str.at(2) = 'z';
|
||||
@@ -331,9 +386,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK(v5.is_string());
|
||||
BOOST_CHECK(v6.is_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "baz");
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "baz");
|
||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::String>(), "baz");
|
||||
BOOST_CHECK_EQUAL(v4.as_string(), "baz");
|
||||
BOOST_CHECK_EQUAL(v5.as_string(), "baz");
|
||||
BOOST_CHECK_EQUAL(v6.as_string(), "baz");
|
||||
|
||||
v1 = true;
|
||||
v2 = true;
|
||||
@@ -355,6 +410,28 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
|
||||
BOOST_CHECK_EQUAL(v2.as_boolean(), true);
|
||||
BOOST_CHECK_EQUAL(v3.as_boolean(), true);
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
std::string_view sv = "foo";
|
||||
|
||||
toml::value v7(sv);
|
||||
toml::value v8(sv, toml::string_t::literal);
|
||||
|
||||
BOOST_CHECK_EQUAL(v7.type(), toml::value_t::String);
|
||||
BOOST_CHECK_EQUAL(v8.type(), toml::value_t::String);
|
||||
BOOST_CHECK(v7.is(toml::value_t::String));
|
||||
BOOST_CHECK(v8.is(toml::value_t::String));
|
||||
BOOST_CHECK(v7.is<toml::String>());
|
||||
BOOST_CHECK(v8.is<toml::String>());
|
||||
BOOST_CHECK(v7.is_string());
|
||||
BOOST_CHECK(v8.is_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(v7.cast<toml::value_t::String>(), "foo");
|
||||
BOOST_CHECK_EQUAL(v8.cast<toml::value_t::String>(), "foo");
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
@@ -368,6 +445,10 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
||||
toml::local_date(2018, toml::month_t::Jan, 31));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_date(),
|
||||
toml::local_date(2018, toml::month_t::Jan, 31));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_date(std::nothrow),
|
||||
toml::local_date(2018, toml::month_t::Jan, 31));
|
||||
|
||||
v1 = toml::local_date(2018, toml::month_t::Apr, 1);
|
||||
|
||||
@@ -378,6 +459,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_date(),
|
||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||
|
||||
toml::value v2(v1);
|
||||
BOOST_CHECK(v2 == v1);
|
||||
@@ -389,6 +472,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDate>(),
|
||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||
BOOST_CHECK_EQUAL(v2.as_local_date(),
|
||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||
|
||||
v1 = true;
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
@@ -396,6 +481,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
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.as_boolean(), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
@@ -415,10 +501,20 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(12, 30, 45));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_time(),
|
||||
toml::local_time(12, 30, 45));
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(12, 30, 45));
|
||||
BOOST_CHECK_EQUAL(v2.as_local_time(),
|
||||
toml::local_time(12, 30, 45));
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||
v2.cast<toml::value_t::LocalTime>());
|
||||
BOOST_CHECK_EQUAL(v1.as_local_time(),
|
||||
v2.as_local_time());
|
||||
BOOST_CHECK_EQUAL(v1.as_local_time(std::nothrow),
|
||||
v2.as_local_time(std::nothrow));
|
||||
|
||||
v1 = toml::local_time(1, 30, 0, /*ms*/ 100, /*us*/ 0);
|
||||
|
||||
@@ -428,6 +524,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
BOOST_CHECK(v1.is_local_time());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(1, 30, 0, 100, 0));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_time(),
|
||||
toml::local_time(1, 30, 0, 100, 0));
|
||||
|
||||
toml::value v3(v1);
|
||||
BOOST_CHECK(v3 == v1);
|
||||
@@ -439,6 +537,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(1, 30, 0, 100, 0));
|
||||
BOOST_CHECK_EQUAL(v3.as_local_time(),
|
||||
toml::local_time(1, 30, 0, 100, 0));
|
||||
|
||||
v1 = true;
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
@@ -446,6 +546,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
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.as_boolean(), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
@@ -464,6 +565,15 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45)));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_datetime(),
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45)));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_datetime(std::nothrow),
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45)));
|
||||
|
||||
|
||||
v1 = toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
@@ -478,6 +588,10 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30)));
|
||||
BOOST_CHECK_EQUAL(v1.as_local_datetime(),
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30)));
|
||||
|
||||
toml::value v2(v1);
|
||||
BOOST_CHECK(v2 == v1);
|
||||
@@ -491,6 +605,11 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30)));
|
||||
BOOST_CHECK_EQUAL(v2.as_local_datetime(),
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30)));
|
||||
|
||||
|
||||
v1 = true;
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
@@ -498,6 +617,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
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.as_boolean(), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
@@ -519,6 +639,19 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
toml::local_time(12, 30, 45),
|
||||
toml::time_offset(9, 0)
|
||||
));
|
||||
BOOST_CHECK_EQUAL(v1.as_offset_datetime(),
|
||||
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.as_offset_datetime(std::nothrow),
|
||||
toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45),
|
||||
toml::time_offset(9, 0)
|
||||
));
|
||||
|
||||
|
||||
v1 = toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
@@ -535,6 +668,12 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30),
|
||||
toml::time_offset(9, 0)));
|
||||
BOOST_CHECK_EQUAL(v1.as_offset_datetime(),
|
||||
toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30),
|
||||
toml::time_offset(9, 0)));
|
||||
|
||||
|
||||
toml::value v2(v1);
|
||||
BOOST_CHECK(v2 == v1);
|
||||
@@ -549,12 +688,19 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30),
|
||||
toml::time_offset(9, 0)));
|
||||
BOOST_CHECK_EQUAL(v2.as_offset_datetime(),
|
||||
toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 1),
|
||||
toml::local_time(1, 15, 30),
|
||||
toml::time_offset(9, 0)));
|
||||
|
||||
v1 = true;
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::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.as_boolean(), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
@@ -578,6 +724,16 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
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(v1.as_array().at(0).as_integer(), 1);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(1).as_integer(), 2);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(2).as_integer(), 3);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(3).as_integer(), 4);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(4).as_integer(), 5);
|
||||
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(0).as_integer(), 1);
|
||||
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(1).as_integer(), 2);
|
||||
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(2).as_integer(), 3);
|
||||
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(3).as_integer(), 4);
|
||||
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(4).as_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);
|
||||
@@ -603,12 +759,24 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 8);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 9);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 0);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(0).as_integer(), 6);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(1).as_integer(), 7);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(2).as_integer(), 8);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(3).as_integer(), 9);
|
||||
BOOST_CHECK_EQUAL(v1.as_array().at(4).as_integer(), 0);
|
||||
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 3);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 4);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 5);
|
||||
BOOST_CHECK_EQUAL(v2.as_array().at(0).as_integer(), 1);
|
||||
BOOST_CHECK_EQUAL(v2.as_array().at(1).as_integer(), 2);
|
||||
BOOST_CHECK_EQUAL(v2.as_array().at(2).as_integer(), 3);
|
||||
BOOST_CHECK_EQUAL(v2.as_array().at(3).as_integer(), 4);
|
||||
BOOST_CHECK_EQUAL(v2.as_array().at(4).as_integer(), 5);
|
||||
|
||||
|
||||
toml::value v3(v1);
|
||||
BOOST_CHECK(v3 == v1);
|
||||
@@ -623,6 +791,12 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 8);
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 9);
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 0);
|
||||
BOOST_CHECK_EQUAL(v3.as_array().at(0).as_integer(), 6);
|
||||
BOOST_CHECK_EQUAL(v3.as_array().at(1).as_integer(), 7);
|
||||
BOOST_CHECK_EQUAL(v3.as_array().at(2).as_integer(), 8);
|
||||
BOOST_CHECK_EQUAL(v3.as_array().at(3).as_integer(), 9);
|
||||
BOOST_CHECK_EQUAL(v3.as_array().at(4).as_integer(), 0);
|
||||
|
||||
|
||||
v1 = true;
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
@@ -630,6 +804,7 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
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.as_boolean(), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
@@ -644,6 +819,13 @@ BOOST_AUTO_TEST_CASE(test_value_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");
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_integer(), 42);
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_floating(), 3.14);
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "qux");
|
||||
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("foo").as_integer(), 42);
|
||||
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("bar").as_floating(), 3.14);
|
||||
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("baz").as_string().str, "qux");
|
||||
|
||||
|
||||
v1 = toml::table{{"foo", 2.71}, {"bar", 54}, {"baz", "quux"}};
|
||||
|
||||
@@ -655,6 +837,10 @@ BOOST_AUTO_TEST_CASE(test_value_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("bar").cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "quux");
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_floating(), 2.71);
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_integer(), 54);
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "quux");
|
||||
|
||||
|
||||
toml::value v3(v1);
|
||||
BOOST_CHECK(v3 == v1);
|
||||
@@ -667,6 +853,10 @@ BOOST_AUTO_TEST_CASE(test_value_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("bar").cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "quux");
|
||||
BOOST_CHECK_EQUAL(v3.as_table().at("foo").as_floating(), 2.71);
|
||||
BOOST_CHECK_EQUAL(v3.as_table().at("bar").as_integer(), 54);
|
||||
BOOST_CHECK_EQUAL(v3.as_table().at("baz").as_string().str, "quux");
|
||||
|
||||
|
||||
v1 = true;
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
@@ -674,6 +864,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
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.as_boolean(), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_empty)
|
||||
@@ -681,4 +872,15 @@ BOOST_AUTO_TEST_CASE(test_value_empty)
|
||||
toml::value v1;
|
||||
BOOST_CHECK(v1.is_uninitialized());
|
||||
BOOST_CHECK(v1.is(toml::value_t::Empty));
|
||||
|
||||
BOOST_CHECK_THROW(v1.as_boolean(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_integer(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_floating(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_string(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_offset_datetime(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_local_datetime(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_local_date(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_local_time(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_array(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.as_table(), toml::type_error);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ inline std::string show_char(const char c)
|
||||
buf.fill('\0');
|
||||
const auto r = std::snprintf(
|
||||
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
|
||||
assert(r == buf.size() - 1);
|
||||
assert(r == static_cast<int>(buf.size()) - 1);
|
||||
return std::string(buf.data());
|
||||
}
|
||||
}
|
||||
@@ -56,31 +56,24 @@ struct character
|
||||
static constexpr char target = C;
|
||||
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
|
||||
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
||||
if(loc.iter() == loc.end()) {return none();}
|
||||
const auto first = loc.iter();
|
||||
|
||||
const char c = *(loc.iter());
|
||||
if(c != target)
|
||||
{
|
||||
if(msg)
|
||||
{
|
||||
return err(concat_to_string("expected '", show_char(target),
|
||||
"' but got '", show_char(c), "'."));
|
||||
}
|
||||
return err("");
|
||||
return none();
|
||||
}
|
||||
loc.advance(); // update location
|
||||
|
||||
return ok(region<Cont>(loc, first, loc.iter()));
|
||||
}
|
||||
|
||||
static std::string pattern() {return show_char(target);}
|
||||
};
|
||||
template<char C>
|
||||
constexpr char character<C>::target;
|
||||
@@ -96,35 +89,24 @@ struct in_range
|
||||
static constexpr char lower = Low;
|
||||
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
|
||||
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
||||
if(loc.iter() == loc.end()) {return none();}
|
||||
const auto first = loc.iter();
|
||||
|
||||
const char c = *(loc.iter());
|
||||
if(c < lower || upper < c)
|
||||
{
|
||||
if(msg)
|
||||
{
|
||||
return err(concat_to_string("expected character in range "
|
||||
"[", show_char(lower), ", ", show_char(upper), "] but got ",
|
||||
"'", show_char(c), "'."));
|
||||
}
|
||||
return err("");
|
||||
return none();
|
||||
}
|
||||
|
||||
loc.advance();
|
||||
return ok(region<Cont>(loc, first, loc.iter()));
|
||||
}
|
||||
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string("[",show_char(lower),"-",show_char(upper),"]");
|
||||
}
|
||||
};
|
||||
template<char L, char U> constexpr char in_range<L, U>::upper;
|
||||
template<char L, char U> constexpr char in_range<L, U>::lower;
|
||||
@@ -135,34 +117,24 @@ template<typename Combinator>
|
||||
struct exclude
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
|
||||
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
||||
if(loc.iter() == loc.end()) {return none();}
|
||||
auto first = loc.iter();
|
||||
|
||||
auto rslt = Combinator::invoke(loc, msg);
|
||||
auto rslt = Combinator::invoke(loc);
|
||||
if(rslt.is_ok())
|
||||
{
|
||||
loc.reset(first);
|
||||
if(msg)
|
||||
{
|
||||
return err(concat_to_string("invalid pattern (",
|
||||
Combinator::pattern(), ") appeared ", rslt.unwrap().str()));
|
||||
}
|
||||
return err("");
|
||||
return none();
|
||||
}
|
||||
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
|
||||
return ok(region<Cont>(loc, first, loc.iter()));
|
||||
}
|
||||
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string("^(", Combinator::pattern(), ')');
|
||||
}
|
||||
};
|
||||
|
||||
// increment `iter`, if matches. otherwise, just return empty string.
|
||||
@@ -170,24 +142,19 @@ template<typename Combinator>
|
||||
struct maybe
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
|
||||
const auto rslt = Combinator::invoke(loc, msg);
|
||||
const auto rslt = Combinator::invoke(loc);
|
||||
if(rslt.is_ok())
|
||||
{
|
||||
return rslt;
|
||||
}
|
||||
return ok(region<Cont>(loc));
|
||||
}
|
||||
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string('(', Combinator::pattern(), ")?");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... Ts>
|
||||
@@ -197,41 +164,35 @@ template<typename Head, typename ... Tail>
|
||||
struct sequence<Head, Tail...>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
|
||||
const auto first = loc.iter();
|
||||
const auto rslt = Head::invoke(loc, msg);
|
||||
const auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
loc.reset(first);
|
||||
return err(rslt.unwrap_err());
|
||||
return none();
|
||||
}
|
||||
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first, msg);
|
||||
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
|
||||
}
|
||||
|
||||
// called from the above function only, recursively.
|
||||
template<typename Cont, typename Iterator>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first,
|
||||
const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
||||
{
|
||||
const auto rslt = Head::invoke(loc, msg);
|
||||
const auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
loc.reset(first);
|
||||
return err(rslt.unwrap_err());
|
||||
return none();
|
||||
}
|
||||
reg += rslt.unwrap(); // concat regions
|
||||
return sequence<Tail...>::invoke(loc, std::move(reg), first, msg);
|
||||
}
|
||||
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string(Head::pattern(), sequence<Tail...>::pattern());
|
||||
return sequence<Tail...>::invoke(loc, std::move(reg), first);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -240,20 +201,18 @@ struct sequence<Head>
|
||||
{
|
||||
// would be called from sequence<T ...>::invoke only.
|
||||
template<typename Cont, typename Iterator>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first,
|
||||
const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
||||
{
|
||||
const auto rslt = Head::invoke(loc, msg);
|
||||
const auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
loc.reset(first);
|
||||
return err(rslt.unwrap_err());
|
||||
return none();
|
||||
}
|
||||
reg += rslt.unwrap(); // concat regions
|
||||
return ok(reg);
|
||||
}
|
||||
static std::string pattern() {return Head::pattern();}
|
||||
};
|
||||
|
||||
template<typename ... Ts>
|
||||
@@ -263,36 +222,27 @@ template<typename Head, typename ... Tail>
|
||||
struct either<Head, Tail...>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
|
||||
const auto rslt = Head::invoke(loc, msg);
|
||||
const auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_ok()) {return rslt;}
|
||||
return either<Tail...>::invoke(loc, msg);
|
||||
}
|
||||
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string('(', Head::pattern(), ")|", either<Tail...>::pattern());
|
||||
return either<Tail...>::invoke(loc);
|
||||
}
|
||||
};
|
||||
template<typename Head>
|
||||
struct either<Head>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
return Head::invoke(loc, msg);
|
||||
}
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string('(', Head::pattern(), ')');
|
||||
return Head::invoke(loc);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -307,52 +257,48 @@ template<typename T, std::size_t N>
|
||||
struct repeat<T, exactly<N>>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
region<Cont> retval(loc);
|
||||
const auto first = loc.iter();
|
||||
for(std::size_t i=0; i<N; ++i)
|
||||
{
|
||||
auto rslt = T::invoke(loc, msg);
|
||||
auto rslt = T::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
loc.reset(first);
|
||||
return err(rslt.unwrap_err());
|
||||
return none();
|
||||
}
|
||||
retval += rslt.unwrap();
|
||||
}
|
||||
return ok(std::move(retval));
|
||||
}
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string('(', T::pattern(), "){", N, '}');
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
struct repeat<T, at_least<N>>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
region<Cont> retval(loc);
|
||||
|
||||
const auto first = loc.iter();
|
||||
for(std::size_t i=0; i<N; ++i)
|
||||
{
|
||||
auto rslt = T::invoke(loc, msg);
|
||||
auto rslt = T::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
loc.reset(first);
|
||||
return err(rslt.unwrap_err());
|
||||
return none();
|
||||
}
|
||||
retval += rslt.unwrap();
|
||||
}
|
||||
while(true)
|
||||
{
|
||||
auto rslt = T::invoke(loc, msg);
|
||||
auto rslt = T::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
return ok(std::move(retval));
|
||||
@@ -360,23 +306,19 @@ struct repeat<T, at_least<N>>
|
||||
retval += rslt.unwrap();
|
||||
}
|
||||
}
|
||||
static std::string pattern()
|
||||
{
|
||||
return concat_to_string('(',T::pattern(), "){", N, ",}");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct repeat<T, unlimited>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, std::string>
|
||||
invoke(location<Cont>& loc, const bool msg = false)
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
{
|
||||
region<Cont> retval(loc);
|
||||
while(true)
|
||||
{
|
||||
auto rslt = T::invoke(loc, msg);
|
||||
auto rslt = T::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
return ok(std::move(retval));
|
||||
@@ -384,7 +326,6 @@ struct repeat<T, unlimited>
|
||||
retval += rslt.unwrap();
|
||||
}
|
||||
}
|
||||
static std::string pattern() {return concat_to_string('(', T::pattern(), ")*");}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -353,15 +353,15 @@ struct local_datetime
|
||||
explicit local_datetime(const std::chrono::system_clock::time_point& tp)
|
||||
{
|
||||
const auto t = std::chrono::system_clock::to_time_t(tp);
|
||||
std::tm time = detail::localtime_s(&t);
|
||||
std::tm ltime = detail::localtime_s(&t);
|
||||
|
||||
this->date = local_date(time);
|
||||
this->time = local_time(time);
|
||||
this->date = local_date(ltime);
|
||||
this->time = local_time(ltime);
|
||||
|
||||
// std::tm lacks subsecond information, so diff between tp and tm
|
||||
// can be used to get millisecond & microsecond information.
|
||||
const auto t_diff = tp -
|
||||
std::chrono::system_clock::from_time_t(std::mktime(&time));
|
||||
std::chrono::system_clock::from_time_t(std::mktime(<ime));
|
||||
this->time.millisecond = static_cast<std::uint16_t>(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
|
||||
this->time.microsecond = static_cast<std::uint16_t>(
|
||||
|
||||
116
toml/get.hpp
116
toml/get.hpp
@@ -108,6 +108,18 @@ inline std::string get(value&& v)
|
||||
return std::move(v.cast<value_t::String>().str);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// std::string_view
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
template<typename T, typename std::enable_if<
|
||||
std::is_same<T, std::string_view>::value, std::nullptr_t>::type = nullptr>
|
||||
inline std::string_view get(const value& v)
|
||||
{
|
||||
return std::string_view(v.cast<value_t::String>().str);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// std::chrono::duration from toml::local_time.
|
||||
|
||||
@@ -264,7 +276,7 @@ namespace detail
|
||||
{
|
||||
|
||||
template<typename T, std::size_t ...I>
|
||||
T get_tuple_impl(const toml::Array& a, index_sequence<I...>)
|
||||
T get_tuple_impl(const toml::array& a, index_sequence<I...>)
|
||||
{
|
||||
return std::make_tuple(
|
||||
::toml::get<typename std::tuple_element<I, T>::type>(a.at(I))...);
|
||||
@@ -507,7 +519,7 @@ std::string get_or(toml::value&& v, T&& opt)
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return opt;
|
||||
return std::forward<T>(opt);
|
||||
}
|
||||
}
|
||||
template<typename T, typename std::enable_if<
|
||||
@@ -529,9 +541,12 @@ std::string get_or(const toml::value& v, 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>>
|
||||
detail::negation<detail::is_exact_toml_type<
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
||||
detail::negation<std::is_same<std::string,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
||||
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)
|
||||
{
|
||||
@@ -542,71 +557,10 @@ T get_or(const toml::value& v, T&& opt)
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return opt;
|
||||
return T(std::move(opt));
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// get_or(table, key, fallback)
|
||||
//
|
||||
// DEPRECATED: use find_or instead.
|
||||
|
||||
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)
|
||||
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
|
||||
{
|
||||
if(tab.count(ky) == 0) {return opt;}
|
||||
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
|
||||
}
|
||||
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)
|
||||
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
|
||||
{
|
||||
if(tab.count(ky) == 0) {return opt;}
|
||||
return ::toml::get_or(tab[ky], std::forward<T>(opt));
|
||||
}
|
||||
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)
|
||||
-> decltype(get_or(std::declval<value&&>(), std::forward<T>(opt)))
|
||||
{
|
||||
if(tab.count(ky) == 0) {return opt;}
|
||||
return ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||
}
|
||||
|
||||
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)
|
||||
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
|
||||
{
|
||||
if(!v.is_table()) {return opt;}
|
||||
const auto& tab = toml::get<toml::table>(v);
|
||||
if(tab.count(ky) == 0) {return opt;}
|
||||
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
|
||||
}
|
||||
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)
|
||||
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
|
||||
{
|
||||
if(!v.is_table()) {return opt;}
|
||||
auto& tab = toml::get<toml::table>(v);
|
||||
if(tab.count(ky) == 0) {return opt;}
|
||||
return ::toml::get_or(tab[ky], std::forward<T>(opt));
|
||||
}
|
||||
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)
|
||||
-> decltype(get_or(std::declval<value&&>(), std::forward<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 ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// find_or(value, key, fallback)
|
||||
|
||||
@@ -666,9 +620,9 @@ 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;}
|
||||
if(!v.is_table()) {return std::forward<T>(opt);}
|
||||
auto tab = toml::get<toml::table>(std::move(v));
|
||||
if(tab.count(ky) == 0) {return opt;}
|
||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
||||
return get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||
}
|
||||
|
||||
@@ -688,9 +642,12 @@ std::string find_or(const toml::value& v, const toml::key& ky, 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>>
|
||||
detail::negation<detail::is_exact_toml_type<
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
||||
detail::negation<std::is_same<std::string,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
||||
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)
|
||||
{
|
||||
@@ -700,8 +657,8 @@ T find_or(const toml::value& v, const toml::key& ky, T&& opt)
|
||||
return get_or(tab.at(ky), std::forward<T>(opt));
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// find_or(table, key, opt)
|
||||
// ---------------------------------------------------------------------------
|
||||
// toml::find(table)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// exact types (return type can be a reference)
|
||||
@@ -749,7 +706,7 @@ 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;}
|
||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
||||
return get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||
}
|
||||
|
||||
@@ -767,9 +724,12 @@ std::string find_or(const toml::table& tab, const toml::key& ky, 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>>
|
||||
detail::negation<detail::is_exact_toml_type<
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
||||
detail::negation<std::is_same<std::string,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ inline namespace literals
|
||||
inline namespace toml_literals
|
||||
{
|
||||
|
||||
inline ::toml::value operator""_toml(const char* str, std::size_t len)
|
||||
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"),
|
||||
@@ -73,6 +73,9 @@ inline ::toml::value operator""_toml(const char* str, std::size_t len)
|
||||
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)));
|
||||
}
|
||||
|
||||
237
toml/parser.hpp
237
toml/parser.hpp
@@ -376,7 +376,7 @@ parse_ml_basic_string(location<Container>& loc)
|
||||
// immediate newline is ignored (if exists)
|
||||
/* discard return value */ lex_newline::invoke(inner_loc);
|
||||
|
||||
delim = err("tmp");
|
||||
delim = none();
|
||||
while(!delim)
|
||||
{
|
||||
using lex_unescaped_seq = repeat<
|
||||
@@ -432,7 +432,7 @@ parse_basic_string(location<Container>& loc)
|
||||
std::string retval;
|
||||
retval.reserve(token.unwrap().size());
|
||||
|
||||
quot = err("tmp");
|
||||
quot = none();
|
||||
while(!quot)
|
||||
{
|
||||
using lex_unescaped_seq = repeat<lex_basic_unescaped, unlimited>;
|
||||
@@ -587,23 +587,17 @@ parse_local_date(location<Container>& loc)
|
||||
const auto y = lex_date_fullyear::invoke(inner_loc);
|
||||
if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
|
||||
{
|
||||
const std::string msg = y.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `-`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_inner_local_date: invalid year format",
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
{{std::addressof(inner_loc), "should be `-`"}}));
|
||||
}
|
||||
inner_loc.advance();
|
||||
const auto m = lex_date_month::invoke(inner_loc);
|
||||
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
|
||||
{
|
||||
const std::string msg = m.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `-`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_date: invalid month format",
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
{{std::addressof(inner_loc), "should be `-`"}}));
|
||||
}
|
||||
inner_loc.advance();
|
||||
const auto d = lex_date_mday::invoke(inner_loc);
|
||||
@@ -611,7 +605,7 @@ parse_local_date(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_date: invalid day format",
|
||||
{{std::addressof(inner_loc), d.unwrap_err()}}));
|
||||
{{std::addressof(inner_loc), "here"}}));
|
||||
}
|
||||
return ok(std::make_pair(local_date(
|
||||
static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0)),
|
||||
@@ -640,23 +634,17 @@ parse_local_time(location<Container>& loc)
|
||||
const auto h = lex_time_hour::invoke(inner_loc);
|
||||
if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
|
||||
{
|
||||
const std::string msg = h.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `:`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid year format",
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
{{std::addressof(inner_loc), "should be `:`"}}));
|
||||
}
|
||||
inner_loc.advance();
|
||||
const auto m = lex_time_minute::invoke(inner_loc);
|
||||
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
|
||||
{
|
||||
const std::string msg = m.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `:`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid month format",
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
{{std::addressof(inner_loc), "should be `:`"}}));
|
||||
}
|
||||
inner_loc.advance();
|
||||
const auto s = lex_time_second::invoke(inner_loc);
|
||||
@@ -664,7 +652,7 @@ parse_local_time(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid second format",
|
||||
{{std::addressof(inner_loc), s.unwrap_err()}}));
|
||||
{{std::addressof(inner_loc), "here"}}));
|
||||
}
|
||||
local_time time(
|
||||
static_cast<std::int8_t>(from_string<int>(h.unwrap().str(), 0)),
|
||||
@@ -700,7 +688,7 @@ parse_local_time(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid subsecond format",
|
||||
{{std::addressof(inner_loc), secfrac.unwrap_err()}}));
|
||||
{{std::addressof(inner_loc), "here"}}));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(time, token.unwrap()));
|
||||
@@ -724,12 +712,9 @@ parse_local_datetime(location<Container>& loc)
|
||||
const auto date = parse_local_date(inner_loc);
|
||||
if(!date || inner_loc.iter() == inner_loc.end())
|
||||
{
|
||||
const std::string msg = date.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "date, not datetime");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_datetime: invalid datetime format",
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
{{std::addressof(inner_loc), "date, not datetime"}}));
|
||||
}
|
||||
const char delim = *(inner_loc.iter());
|
||||
if(delim != 'T' && delim != 't' && delim != ' ')
|
||||
@@ -769,12 +754,9 @@ parse_offset_datetime(location<Container>& loc)
|
||||
const auto datetime = parse_local_datetime(inner_loc);
|
||||
if(!datetime || inner_loc.iter() == inner_loc.end())
|
||||
{
|
||||
const std::string msg = datetime.map_err_or_else(
|
||||
[](const std::string& msg){return msg;}, "date, not datetime");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_offset_datetime: invalid datetime format",
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
{{std::addressof(inner_loc), "date, not datetime"}}));
|
||||
}
|
||||
time_offset offset(0, 0);
|
||||
if(const auto ofs = lex_time_numoffset::invoke(inner_loc))
|
||||
@@ -1167,7 +1149,7 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
{
|
||||
if(tab->count(k) == 1) // there is already an array of table
|
||||
{
|
||||
if(tab->at(k).is(value_t::Table))
|
||||
if(tab->at(k).is_table())
|
||||
{
|
||||
// show special err msg for conflicting table
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
@@ -1180,7 +1162,7 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
"this conflicts with the previous table"}
|
||||
}));
|
||||
}
|
||||
else if(!(tab->at(k).is(value_t::Array)))
|
||||
else if(!(tab->at(k).is_array()))
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of table (\"",
|
||||
@@ -1193,8 +1175,9 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
"while inserting this array-of-tables"}
|
||||
}));
|
||||
}
|
||||
array& a = tab->at(k).template cast<toml::value_t::Array>();
|
||||
if(!(a.front().is(value_t::Table)))
|
||||
// the above if-else-if checks tab->at(k) is an array
|
||||
array& a = tab->at(k).as_array();
|
||||
if(!(a.front().is_table()))
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of table (\"",
|
||||
@@ -1248,7 +1231,7 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
|
||||
if(tab->count(k) == 1)
|
||||
{
|
||||
if(tab->at(k).is(value_t::Table) && v.is(value_t::Table))
|
||||
if(tab->at(k).is_table() && v.is_table())
|
||||
{
|
||||
if(!is_valid_forward_table_definition(
|
||||
tab->at(k), first, iter, last))
|
||||
@@ -1268,18 +1251,18 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
// d = 42
|
||||
// [a]
|
||||
// e = 2.71
|
||||
auto& t = tab->at(k).cast<value_t::Table>();
|
||||
for(const auto& kv : v.cast<value_t::Table>())
|
||||
auto& t = tab->at(k).as_table();
|
||||
for(const auto& kv : v.as_table())
|
||||
{
|
||||
t[kv.first] = kv.second;
|
||||
}
|
||||
detail::change_region(tab->at(k), key_reg);
|
||||
return ok(true);
|
||||
}
|
||||
else if(v.is(value_t::Table) &&
|
||||
tab->at(k).is(value_t::Array) &&
|
||||
tab->at(k).cast<value_t::Array>().size() > 0 &&
|
||||
tab->at(k).cast<value_t::Array>().front().is(value_t::Table))
|
||||
else if(v.is_table() &&
|
||||
tab->at(k).is_array() &&
|
||||
tab->at(k).as_array().size() > 0 &&
|
||||
tab->at(k).as_array().front().is_table())
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of tables (\"",
|
||||
@@ -1319,14 +1302,14 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
}
|
||||
|
||||
// type checking...
|
||||
if(tab->at(k).is(value_t::Table))
|
||||
if(tab->at(k).is_table())
|
||||
{
|
||||
tab = std::addressof((*tab)[k].template cast<value_t::Table>());
|
||||
tab = std::addressof((*tab)[k].as_table());
|
||||
}
|
||||
else if(tab->at(k).is(value_t::Array)) // inserting to array-of-tables?
|
||||
else if(tab->at(k).is_array()) // inserting to array-of-tables?
|
||||
{
|
||||
array& a = (*tab)[k].template cast<value_t::Array>();
|
||||
if(!a.back().is(value_t::Table))
|
||||
array& a = (*tab)[k].as_array();
|
||||
if(!a.back().is_table())
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: target (",
|
||||
@@ -1337,7 +1320,7 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
{std::addressof(get_region(v)), "inserting this"}
|
||||
}));
|
||||
}
|
||||
tab = std::addressof(a.back().template cast<value_t::Table>());
|
||||
tab = std::addressof(a.back().as_table());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1363,7 +1346,7 @@ parse_inline_table(location<Container>& loc)
|
||||
table retval;
|
||||
if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
|
||||
{
|
||||
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"}}));
|
||||
}
|
||||
loc.advance();
|
||||
@@ -1427,41 +1410,156 @@ parse_inline_table(location<Container>& loc)
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
value_t guess_number_type(const location<Container>& l)
|
||||
result<value_t, std::string> guess_number_type(const location<Container>& l)
|
||||
{
|
||||
// This function tries to find some (common) mistakes by checking characters
|
||||
// that follows the last character of a value. But it is often difficult
|
||||
// because some non-newline characters can appear after a value. E.g.
|
||||
// spaces, tabs, commas (in an array or inline table), closing brackets
|
||||
// (of an array or inline table), comment-sign (#). Since this function
|
||||
// does not parse further, those characters are always allowed to be there.
|
||||
location<Container> loc = l;
|
||||
|
||||
if(lex_offset_date_time::invoke(loc)) {return value_t::OffsetDatetime;}
|
||||
if(lex_offset_date_time::invoke(loc)) {return ok(value_t::OffsetDatetime);}
|
||||
loc.reset(l.iter());
|
||||
|
||||
if(lex_local_date_time::invoke(loc)) {return value_t::LocalDatetime;}
|
||||
if(lex_local_date_time::invoke(loc))
|
||||
{
|
||||
// bad offset may appear after this.
|
||||
if(loc.iter() != loc.end() && (*loc.iter() == '+' || *loc.iter() == '-'
|
||||
|| *loc.iter() == 'Z' || *loc.iter() == 'z'))
|
||||
{
|
||||
return err(format_underline("[error] bad offset: should be [+-]HH:MM or Z",
|
||||
{{std::addressof(loc), "[+-]HH:MM or Z"}},
|
||||
{"pass: +09:00, -05:30", "fail: +9:00, -5:30"}));
|
||||
}
|
||||
return ok(value_t::LocalDatetime);
|
||||
}
|
||||
loc.reset(l.iter());
|
||||
|
||||
if(lex_local_date::invoke(loc)) {return value_t::LocalDate;}
|
||||
if(lex_local_date::invoke(loc))
|
||||
{
|
||||
// bad time may appear after this.
|
||||
// A space is allowed as a delimiter between local time. But there are
|
||||
// both cases in which a space becomes valid or invalid.
|
||||
// - invalid: 2019-06-16 7:00:00
|
||||
// - valid : 2019-06-16 07:00:00
|
||||
if(loc.iter() != loc.end())
|
||||
{
|
||||
const auto c = *loc.iter();
|
||||
if(c == 'T' || c == 't')
|
||||
{
|
||||
return err(format_underline("[error] bad time: should be HH:MM:SS.subsec",
|
||||
{{std::addressof(loc), "HH:MM:SS.subsec"}},
|
||||
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
|
||||
"fail: 1979-05-27T7:32:00, 1979-05-27 17:32"}));
|
||||
}
|
||||
if('0' <= c && c <= '9')
|
||||
{
|
||||
return err(format_underline("[error] bad time: missing T",
|
||||
{{std::addressof(loc), "T or space required here"}},
|
||||
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
|
||||
"fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
|
||||
}
|
||||
if(c == ' ' && std::next(loc.iter()) != loc.end() &&
|
||||
('0' <= *std::next(loc.iter()) && *std::next(loc.iter())<= '9'))
|
||||
{
|
||||
loc.advance();
|
||||
return err(format_underline("[error] bad time: should be HH:MM:SS.subsec",
|
||||
{{std::addressof(loc), "HH:MM:SS.subsec"}},
|
||||
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
|
||||
"fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
|
||||
}
|
||||
}
|
||||
return ok(value_t::LocalDate);
|
||||
}
|
||||
loc.reset(l.iter());
|
||||
|
||||
if(lex_local_time::invoke(loc)) {return value_t::LocalTime;}
|
||||
if(lex_local_time::invoke(loc)) {return ok(value_t::LocalTime);}
|
||||
loc.reset(l.iter());
|
||||
|
||||
if(lex_float::invoke(loc)) {return value_t::Float;}
|
||||
if(lex_float::invoke(loc))
|
||||
{
|
||||
if(loc.iter() != loc.end() && *loc.iter() == '_')
|
||||
{
|
||||
return err(format_underline("[error] bad float: `_` should be surrounded by digits",
|
||||
{{std::addressof(loc), "here"}},
|
||||
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
|
||||
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
|
||||
}
|
||||
return ok(value_t::Float);
|
||||
}
|
||||
loc.reset(l.iter());
|
||||
|
||||
return value_t::Integer;
|
||||
if(lex_integer::invoke(loc))
|
||||
{
|
||||
if(loc.iter() != loc.end())
|
||||
{
|
||||
const auto c = *loc.iter();
|
||||
if(c == '_')
|
||||
{
|
||||
return err(format_underline("[error] bad integer: `_` should be surrounded by digits",
|
||||
{{std::addressof(loc), "here"}},
|
||||
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
|
||||
"fail: 1__000, 0123"}));
|
||||
}
|
||||
if('0' <= c && c <= '9')
|
||||
{
|
||||
// leading zero. point '0'
|
||||
loc.retrace();
|
||||
return err(format_underline("[error] bad integer: leading zero",
|
||||
{{std::addressof(loc), "here"}},
|
||||
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
|
||||
"fail: 1__000, 0123"}));
|
||||
}
|
||||
if(c == ':' || c == '-')
|
||||
{
|
||||
return err(format_underline("[error] bad datetime: invalid format",
|
||||
{{std::addressof(loc), "here"}},
|
||||
{"pass: 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z",
|
||||
"fail: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30"}));
|
||||
}
|
||||
if(c == '.' || c == 'e' || c == 'E')
|
||||
{
|
||||
return err(format_underline("[error] bad float: invalid format",
|
||||
{{std::addressof(loc), "here"}},
|
||||
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
|
||||
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
|
||||
}
|
||||
}
|
||||
return ok(value_t::Integer);
|
||||
}
|
||||
if(loc.iter() != loc.end() && *loc.iter() == '.')
|
||||
{
|
||||
return err(format_underline("[error] bad float: invalid format",
|
||||
{{std::addressof(loc), "integer part required before this"}},
|
||||
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
|
||||
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
|
||||
}
|
||||
if(loc.iter() != loc.end() && *loc.iter() == '_')
|
||||
{
|
||||
return err(format_underline("[error] bad number: `_` should be surrounded by digits",
|
||||
{{std::addressof(loc), "`_` is not surrounded by digits"}},
|
||||
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
|
||||
"fail: 1__000, 0123"}));
|
||||
}
|
||||
return err(format_underline("[error] bad format: unknown value appeared",
|
||||
{{std::addressof(loc), "here"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
value_t guess_value_type(const location<Container>& loc)
|
||||
result<value_t, std::string> 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.
|
||||
case '"' : {return ok(value_t::String); }
|
||||
case '\'': {return ok(value_t::String); }
|
||||
case 't' : {return ok(value_t::Boolean);}
|
||||
case 'f' : {return ok(value_t::Boolean);}
|
||||
case '[' : {return ok(value_t::Array); }
|
||||
case '{' : {return ok(value_t::Table); }
|
||||
case 'i' : {return ok(value_t::Float); } // inf.
|
||||
case 'n' : {return ok(value_t::Float); } // nan.
|
||||
default : {return guess_number_type(loc);}
|
||||
}
|
||||
}
|
||||
@@ -1476,7 +1574,12 @@ result<value, std::string> parse_value(location<Container>& loc)
|
||||
{{std::addressof(loc), ""}}));
|
||||
}
|
||||
|
||||
switch(guess_value_type(loc))
|
||||
const auto type = guess_value_type(loc);
|
||||
if(!type)
|
||||
{
|
||||
return err(type.unwrap_err());
|
||||
}
|
||||
switch(type.unwrap())
|
||||
{
|
||||
case value_t::Boolean : {return parse_boolean(loc); }
|
||||
case value_t::Integer : {return parse_integer(loc); }
|
||||
@@ -1560,7 +1663,7 @@ template<typename Container>
|
||||
result<std::pair<std::vector<key>, region<Container>>, std::string>
|
||||
parse_array_table_key(location<Container>& loc)
|
||||
{
|
||||
if(auto token = lex_array_table::invoke(loc, true))
|
||||
if(auto token = lex_array_table::invoke(loc))
|
||||
{
|
||||
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||
|
||||
@@ -1672,12 +1775,12 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
||||
const auto newline = skip_line::invoke(loc);
|
||||
if(!newline && loc.iter() != loc.end())
|
||||
{
|
||||
const auto before = loc.iter();
|
||||
const auto before2 = loc.iter();
|
||||
lex_ws::invoke(loc); // skip whitespace
|
||||
const auto msg = format_underline("[error] toml::parse_table: "
|
||||
"invalid line format", {{std::addressof(loc), concat_to_string(
|
||||
"expected newline, but got '", show_char(*loc.iter()), "'.")}});
|
||||
loc.reset(before);
|
||||
loc.reset(before2);
|
||||
return err(msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,14 @@ struct region_base
|
||||
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::string comment_before() const {return "";} // just before
|
||||
virtual std::string comment_inline() const {return "";} // in the same line
|
||||
virtual std::string comment() const {return "";} // concatenate
|
||||
// ```toml
|
||||
// # comment_before
|
||||
// key = "value" # comment_inline
|
||||
// ```
|
||||
};
|
||||
|
||||
// location represents a position in a container, which contains a file content.
|
||||
@@ -280,6 +288,92 @@ struct region final : public region_base
|
||||
|
||||
std::string name() const override {return source_name_;}
|
||||
|
||||
std::string comment_before() const override
|
||||
{
|
||||
auto iter = this->line_begin(); // points the first element
|
||||
std::vector<std::pair<decltype(iter), decltype(iter)>> comments;
|
||||
while(iter != this->begin())
|
||||
{
|
||||
iter = std::prev(iter);
|
||||
using rev_iter = std::reverse_iterator<decltype(iter)>;
|
||||
auto line_before = std::find(rev_iter(iter), rev_iter(this->begin()),
|
||||
'\n').base();
|
||||
// range [line_before, iter) represents the previous line
|
||||
|
||||
auto comment_found = std::find(line_before, iter, '#');
|
||||
if(iter != comment_found && std::all_of(line_before, comment_found,
|
||||
[](const char c) noexcept -> bool {
|
||||
return c == ' ' || c == '\t';
|
||||
}))
|
||||
{
|
||||
// the line before this range contains only a comment.
|
||||
comments.push_back(std::make_pair(comment_found, iter));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
iter = line_before;
|
||||
}
|
||||
|
||||
std::string com;
|
||||
for(auto i = comments.crbegin(), e = comments.crend(); i!=e; ++i)
|
||||
{
|
||||
if(i != comments.crbegin()) {com += '\n';}
|
||||
com += std::string(i->first, i->second);
|
||||
}
|
||||
return com;
|
||||
}
|
||||
|
||||
std::string comment_inline() const override
|
||||
{
|
||||
if(this->contain_newline())
|
||||
{
|
||||
std::string com;
|
||||
// check both the first and the last line.
|
||||
const auto first_line_end =
|
||||
std::find(this->line_begin(), this->last(), '\n');
|
||||
const auto first_comment_found =
|
||||
std::find(this->line_begin(), first_line_end, '#');
|
||||
|
||||
if(first_comment_found != first_line_end)
|
||||
{
|
||||
com += std::string(first_comment_found, first_line_end);
|
||||
}
|
||||
|
||||
const auto last_comment_found =
|
||||
std::find(this->last(), this->line_end(), '#');
|
||||
if(last_comment_found != this->line_end())
|
||||
{
|
||||
if(!com.empty()){com += '\n';}
|
||||
com += std::string(last_comment_found, this->line_end());
|
||||
}
|
||||
return com;
|
||||
}
|
||||
const auto comment_found =
|
||||
std::find(this->line_begin(), this->line_end(), '#');
|
||||
return std::string(comment_found, this->line_end());
|
||||
}
|
||||
|
||||
std::string comment() const override
|
||||
{
|
||||
std::string com_bef = this->comment_before();
|
||||
std::string com_inl = this->comment_inline();
|
||||
if(!com_bef.empty() && !com_inl.empty())
|
||||
{
|
||||
com_bef += '\n';
|
||||
return com_bef + com_inl;
|
||||
}
|
||||
else if(com_bef.empty())
|
||||
{
|
||||
return com_inl;
|
||||
}
|
||||
else
|
||||
{
|
||||
return com_bef;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
source_ptr source_;
|
||||
@@ -343,7 +437,8 @@ inline std::string format_underline(const std::string& message,
|
||||
{
|
||||
// invalid
|
||||
// ~~~~~~~
|
||||
retval << make_string(reg->size(), '~');
|
||||
const auto underline_len = std::min(reg->size(), reg->line().size());
|
||||
retval << make_string(underline_len, '~');
|
||||
}
|
||||
|
||||
retval << ' ';
|
||||
|
||||
@@ -113,21 +113,25 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(s);
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
result(const failure_type& f): is_ok_(false)
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
result(success_type&& s): is_ok_(true)
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
result(failure_type&& f): is_ok_(false)
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
@@ -135,24 +139,28 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
template<typename U>
|
||||
result(const failure<U>& f): is_ok_(false)
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
template<typename U>
|
||||
result(success<U>&& s): is_ok_(true)
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
template<typename U>
|
||||
result(failure<U>&& f): is_ok_(false)
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
|
||||
result& operator=(const success_type& s)
|
||||
@@ -161,6 +169,7 @@ struct result
|
||||
this->is_ok_ = true;
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(s);
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
result& operator=(const failure_type& f)
|
||||
@@ -169,6 +178,7 @@ struct result
|
||||
this->is_ok_ = false;
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
result& operator=(success_type&& s)
|
||||
@@ -177,6 +187,7 @@ struct result
|
||||
this->is_ok_ = true;
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
result& operator=(failure_type&& f)
|
||||
@@ -185,6 +196,7 @@ struct result
|
||||
this->is_ok_ = false;
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -195,6 +207,7 @@ struct result
|
||||
this->is_ok_ = true;
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
template<typename U>
|
||||
@@ -204,6 +217,7 @@ struct result
|
||||
this->is_ok_ = false;
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
template<typename U>
|
||||
@@ -213,6 +227,7 @@ struct result
|
||||
this->is_ok_ = true;
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
template<typename U>
|
||||
@@ -222,6 +237,7 @@ struct result
|
||||
this->is_ok_ = false;
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -233,11 +249,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
}
|
||||
result(result&& other): is_ok_(other.is_ok())
|
||||
@@ -246,11 +264,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,11 +281,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
}
|
||||
template<typename U, typename F>
|
||||
@@ -275,11 +297,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,11 +314,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
is_ok_ = other.is_ok();
|
||||
return *this;
|
||||
@@ -306,11 +332,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
is_ok_ = other.is_ok();
|
||||
return *this;
|
||||
@@ -324,11 +352,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
is_ok_ = other.is_ok();
|
||||
return *this;
|
||||
@@ -341,11 +371,13 @@ struct result
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
||||
assert(tmp == std::addressof(this->succ));
|
||||
(void)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
||||
assert(tmp == std::addressof(this->fail));
|
||||
(void)tmp;
|
||||
}
|
||||
is_ok_ = other.is_ok();
|
||||
return *this;
|
||||
@@ -660,5 +692,26 @@ void swap(result<T, E>& lhs, result<T, E>& rhs)
|
||||
// return lhs.is_ok() ? lhs : rhs;
|
||||
// }
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// re-use result<T, E> as a optional<T> with none_t
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct none_t {};
|
||||
inline bool operator==(const none_t&, const none_t&) noexcept {return true;}
|
||||
inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}
|
||||
inline bool operator< (const none_t&, const none_t&) noexcept {return false;}
|
||||
inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}
|
||||
inline bool operator> (const none_t&, const none_t&) noexcept {return false;}
|
||||
inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}
|
||||
template<typename charT, typename traitsT>
|
||||
std::basic_ostream<charT, traitsT>&
|
||||
operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
|
||||
{
|
||||
os << "none";
|
||||
return os;
|
||||
}
|
||||
inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
|
||||
} // detail
|
||||
} // toml11
|
||||
#endif// TOML11_RESULT_H
|
||||
|
||||
@@ -157,7 +157,7 @@ struct serializer
|
||||
|
||||
std::string operator()(const array& v) const
|
||||
{
|
||||
if(!v.empty() && v.front().is(value_t::Table))// v is an array of tables
|
||||
if(!v.empty() && v.front().is_table())// v is an array of tables
|
||||
{
|
||||
// if it's not inlined, we need to add `[[table.key]]`.
|
||||
// but if it can be inlined, we need `table.key = [...]`.
|
||||
@@ -411,7 +411,7 @@ struct serializer
|
||||
// remaining non-table values will be assigned into [foo.bar], not [foo]
|
||||
for(const auto kv : v)
|
||||
{
|
||||
if(kv.second.is(value_t::Table) || is_array_of_tables(kv.second))
|
||||
if(kv.second.is_table() || is_array_of_tables(kv.second))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -438,7 +438,7 @@ struct serializer
|
||||
bool multiline_table_printed = false;
|
||||
for(const auto& kv : v)
|
||||
{
|
||||
if(!kv.second.is(value_t::Table) && !is_array_of_tables(kv.second))
|
||||
if(!kv.second.is_table() && !is_array_of_tables(kv.second))
|
||||
{
|
||||
continue; // other stuff are already serialized. skip them.
|
||||
}
|
||||
@@ -467,10 +467,9 @@ struct serializer
|
||||
|
||||
bool is_array_of_tables(const value& v) const
|
||||
{
|
||||
if(!v.is(value_t::Array)) {return false;}
|
||||
|
||||
const auto& a = v.cast<value_t::Array>();
|
||||
return !a.empty() && a.front().is(value_t::Table);
|
||||
if(!v.is_array()) {return false;}
|
||||
const auto& a = v.as_array();
|
||||
return !a.empty() && a.front().is_table();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
#define TOML11_STRING_HPP
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#if __cplusplus >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
#include <string_view>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -40,6 +45,17 @@ struct string
|
||||
operator std::string const& () const& noexcept {return str;}
|
||||
operator std::string&& () && noexcept {return std::move(str);}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
||||
string(std::string_view s, string_t k): kind(k), str(s){}
|
||||
|
||||
string& operator=(std::string_view s)
|
||||
{kind = string_t::basic; str = s; return *this;}
|
||||
|
||||
explicit operator std::string_view() const noexcept
|
||||
{return std::string_view(str);}
|
||||
#endif
|
||||
|
||||
string_t kind;
|
||||
std::string str;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
#include <utility>
|
||||
#include <chrono>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#if __cplusplus >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
#include <string_view>
|
||||
#endif // has_include(<string_view>)
|
||||
#endif // cplusplus >= C++17
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -81,7 +87,6 @@ struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
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)){};
|
||||
@@ -114,7 +119,7 @@ template<typename T>
|
||||
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// normal type checker
|
||||
// type checkers
|
||||
|
||||
template<typename T> struct is_std_pair : std::false_type{};
|
||||
template<typename T1, typename T2>
|
||||
@@ -128,6 +133,33 @@ template<typename T> struct is_chrono_duration: std::false_type{};
|
||||
template<typename Rep, typename Period>
|
||||
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
|
||||
|
||||
template<typename T>
|
||||
struct is_map : conjunction< // map satisfies all the following conditions
|
||||
has_iterator<T>, // has T::iterator
|
||||
has_value_type<T>, // has T::value_type
|
||||
has_key_type<T>, // has T::key_type
|
||||
has_mapped_type<T> // has T::mapped_type
|
||||
>{};
|
||||
template<typename T> struct is_map<T&> : is_map<T>{};
|
||||
template<typename T> struct is_map<T const&> : is_map<T>{};
|
||||
template<typename T> struct is_map<T volatile&> : is_map<T>{};
|
||||
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
|
||||
|
||||
template<typename T>
|
||||
struct is_container : conjunction<
|
||||
negation<is_map<T>>, // not a map
|
||||
negation<std::is_same<T, std::string>>, // not a std::string
|
||||
#if __cplusplus >= 201703L
|
||||
negation<std::is_same<T, std::string_view>>, // not a std::string_view
|
||||
#endif
|
||||
has_iterator<T>, // has T::iterator
|
||||
has_value_type<T> // has T::value_type
|
||||
>{};
|
||||
template<typename T> struct is_container<T&> : is_container<T>{};
|
||||
template<typename T> struct is_container<T const&> : is_container<T>{};
|
||||
template<typename T> struct is_container<T volatile&> : is_container<T>{};
|
||||
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++14 index_sequence
|
||||
|
||||
|
||||
@@ -126,61 +126,36 @@ template<> struct toml_default_type<value_t::Table > {typedef table
|
||||
template<> struct toml_default_type<value_t::Empty > {typedef void type;};
|
||||
template<> struct toml_default_type<value_t::Unknown > {typedef void type;};
|
||||
|
||||
template<typename T> struct toml_value_t {static constexpr value_t value = value_t::Unknown ;};
|
||||
template<> struct toml_value_t<Boolean >{static constexpr value_t value = value_t::Boolean ;};
|
||||
template<> struct toml_value_t<Integer >{static constexpr value_t value = value_t::Integer ;};
|
||||
template<> struct toml_value_t<Float >{static constexpr value_t value = value_t::Float ;};
|
||||
template<> struct toml_value_t<String >{static constexpr value_t value = value_t::String ;};
|
||||
template<> struct toml_value_t<OffsetDatetime>{static constexpr value_t value = value_t::OffsetDatetime;};
|
||||
template<> struct toml_value_t<LocalDatetime >{static constexpr value_t value = value_t::LocalDatetime ;};
|
||||
template<> struct toml_value_t<LocalDate >{static constexpr value_t value = value_t::LocalDate ;};
|
||||
template<> struct toml_value_t<LocalTime >{static constexpr value_t value = value_t::LocalTime ;};
|
||||
template<> struct toml_value_t<Array >{static constexpr value_t value = value_t::Array ;};
|
||||
template<> struct toml_value_t<Table >{static constexpr value_t value = value_t::Table ;};
|
||||
template<typename T> struct toml_value_t {static constexpr value_t value = value_t::Unknown ;};
|
||||
template<> struct toml_value_t<boolean >{static constexpr value_t value = value_t::Boolean ;};
|
||||
template<> struct toml_value_t<integer >{static constexpr value_t value = value_t::Integer ;};
|
||||
template<> struct toml_value_t<floating >{static constexpr value_t value = value_t::Float ;};
|
||||
template<> struct toml_value_t<string >{static constexpr value_t value = value_t::String ;};
|
||||
template<> struct toml_value_t<offset_datetime>{static constexpr value_t value = value_t::OffsetDatetime;};
|
||||
template<> struct toml_value_t<local_datetime >{static constexpr value_t value = value_t::LocalDatetime ;};
|
||||
template<> struct toml_value_t<local_date >{static constexpr value_t value = value_t::LocalDate ;};
|
||||
template<> struct toml_value_t<local_time >{static constexpr value_t value = value_t::LocalTime ;};
|
||||
template<> struct toml_value_t<array >{static constexpr value_t value = value_t::Array ;};
|
||||
template<> struct toml_value_t<table >{static constexpr value_t value = value_t::Table ;};
|
||||
|
||||
template<typename T>
|
||||
struct is_exact_toml_type : disjunction<
|
||||
std::is_same<T, Boolean >,
|
||||
std::is_same<T, Integer >,
|
||||
std::is_same<T, Float >,
|
||||
std::is_same<T, String >,
|
||||
std::is_same<T, boolean >,
|
||||
std::is_same<T, integer >,
|
||||
std::is_same<T, floating >,
|
||||
std::is_same<T, string >,
|
||||
std::is_same<T, offset_datetime>,
|
||||
std::is_same<T, local_datetime>,
|
||||
std::is_same<T, local_date>,
|
||||
std::is_same<T, local_time>,
|
||||
std::is_same<T, Array >,
|
||||
std::is_same<T, Table >
|
||||
std::is_same<T, local_datetime >,
|
||||
std::is_same<T, local_date >,
|
||||
std::is_same<T, local_time >,
|
||||
std::is_same<T, array >,
|
||||
std::is_same<T, table >
|
||||
>{};
|
||||
template<typename T> struct is_exact_toml_type<T&> : is_exact_toml_type<T>{};
|
||||
template<typename T> struct is_exact_toml_type<T const&> : is_exact_toml_type<T>{};
|
||||
template<typename T> struct is_exact_toml_type<T volatile&> : is_exact_toml_type<T>{};
|
||||
template<typename T> struct is_exact_toml_type<T const volatile&>: is_exact_toml_type<T>{};
|
||||
|
||||
template<typename T>
|
||||
struct is_map : conjunction<
|
||||
has_iterator<T>,
|
||||
has_value_type<T>,
|
||||
has_key_type<T>,
|
||||
has_mapped_type<T>
|
||||
>{};
|
||||
template<typename T> struct is_map<T&> : is_map<T>{};
|
||||
template<typename T> struct is_map<T const&> : is_map<T>{};
|
||||
template<typename T> struct is_map<T volatile&> : is_map<T>{};
|
||||
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
|
||||
|
||||
template<typename T>
|
||||
struct is_container : conjunction<
|
||||
negation<is_map<T>>,
|
||||
negation<std::is_same<T, std::string>>,
|
||||
has_iterator<T>,
|
||||
has_value_type<T>
|
||||
>{};
|
||||
template<typename T> struct is_container<T&> : is_container<T>{};
|
||||
template<typename T> struct is_container<T const&> : is_container<T>{};
|
||||
template<typename T> struct is_container<T volatile&> : is_container<T>{};
|
||||
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
|
||||
|
||||
|
||||
} // detail
|
||||
} // toml
|
||||
#endif// TOML11_TYPES_H
|
||||
|
||||
@@ -79,7 +79,7 @@ std::string concat_to_string(Ts&& ... args)
|
||||
template<typename T, typename U>
|
||||
T from_string(const std::string& str, U&& opt)
|
||||
{
|
||||
T v(std::forward<U>(opt));
|
||||
T v(static_cast<T>(std::forward<U>(opt)));
|
||||
std::istringstream iss(str);
|
||||
iss >> v;
|
||||
return v;
|
||||
|
||||
722
toml/value.hpp
722
toml/value.hpp
@@ -14,6 +14,9 @@
|
||||
#include <unordered_map>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#if __cplusplus >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -24,6 +27,16 @@ namespace detail
|
||||
region_base const& get_region(const value&);
|
||||
template<typename Region>
|
||||
void change_region(value&, Region&&);
|
||||
|
||||
template<value_t Expected>
|
||||
[[noreturn]] inline void throw_bad_cast(value_t actual, const ::toml::value& v)
|
||||
{
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", Expected), {
|
||||
{std::addressof(get_region(v)),
|
||||
concat_to_string("the actual type is ", actual)}
|
||||
}));
|
||||
}
|
||||
}// detail
|
||||
|
||||
template<typename T>
|
||||
@@ -45,6 +58,7 @@ class value
|
||||
{
|
||||
const auto tmp = ::new(std::addressof(dst)) T(std::forward<U>(v));
|
||||
assert(tmp == std::addressof(dst));
|
||||
(void)tmp;
|
||||
}
|
||||
|
||||
using region_base = detail::region_base;
|
||||
@@ -293,6 +307,29 @@ class value
|
||||
assigner(this->string_, toml::string(std::string(s), kind));
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
value(std::string_view s)
|
||||
: type_(value_t::String),
|
||||
region_info_(std::make_shared<region_base>(region_base{}))
|
||||
{
|
||||
assigner(this->string_, toml::string(s));
|
||||
}
|
||||
value& operator=(std::string_view s)
|
||||
{
|
||||
this->cleanup();
|
||||
this->type_ = value_t::String;
|
||||
this->region_info_ = std::make_shared<region_base>(region_base{});
|
||||
assigner(this->string_, toml::string(s));
|
||||
return *this;
|
||||
}
|
||||
value(std::string_view s, string_t kind)
|
||||
: type_(value_t::String),
|
||||
region_info_(std::make_shared<region_base>(region_base{}))
|
||||
{
|
||||
assigner(this->string_, toml::string(s, kind));
|
||||
}
|
||||
#endif
|
||||
|
||||
// local date ===========================================================
|
||||
|
||||
value(const local_date& ld)
|
||||
@@ -589,7 +626,7 @@ class value
|
||||
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_floating() 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 );}
|
||||
@@ -607,6 +644,367 @@ class value
|
||||
template<value_t T>
|
||||
typename detail::toml_default_type<T>::type&& cast() &&;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// nothrow version
|
||||
|
||||
boolean const& as_boolean (const std::nothrow_t&) const& noexcept {return this->boolean_;}
|
||||
integer const& as_integer (const std::nothrow_t&) const& noexcept {return this->integer_;}
|
||||
floating const& as_floating (const std::nothrow_t&) const& noexcept {return this->floating_;}
|
||||
string const& as_string (const std::nothrow_t&) const& noexcept {return this->string_;}
|
||||
offset_datetime const& as_offset_datetime(const std::nothrow_t&) const& noexcept {return this->offset_datetime_;}
|
||||
local_datetime const& as_local_datetime (const std::nothrow_t&) const& noexcept {return this->local_datetime_;}
|
||||
local_date const& as_local_date (const std::nothrow_t&) const& noexcept {return this->local_date_;}
|
||||
local_time const& as_local_time (const std::nothrow_t&) const& noexcept {return this->local_time_;}
|
||||
array const& as_array (const std::nothrow_t&) const& noexcept {return this->array_.value();}
|
||||
table const& as_table (const std::nothrow_t&) const& noexcept {return this->table_.value();}
|
||||
|
||||
boolean & as_boolean (const std::nothrow_t&) & noexcept {return this->boolean_;}
|
||||
integer & as_integer (const std::nothrow_t&) & noexcept {return this->integer_;}
|
||||
floating & as_floating (const std::nothrow_t&) & noexcept {return this->floating_;}
|
||||
string & as_string (const std::nothrow_t&) & noexcept {return this->string_;}
|
||||
offset_datetime& as_offset_datetime(const std::nothrow_t&) & noexcept {return this->offset_datetime_;}
|
||||
local_datetime & as_local_datetime (const std::nothrow_t&) & noexcept {return this->local_datetime_;}
|
||||
local_date & as_local_date (const std::nothrow_t&) & noexcept {return this->local_date_;}
|
||||
local_time & as_local_time (const std::nothrow_t&) & noexcept {return this->local_time_;}
|
||||
array & as_array (const std::nothrow_t&) & noexcept {return this->array_.value();}
|
||||
table & as_table (const std::nothrow_t&) & noexcept {return this->table_.value();}
|
||||
|
||||
boolean && as_boolean (const std::nothrow_t&) && noexcept {return std::move(this->boolean_);}
|
||||
integer && as_integer (const std::nothrow_t&) && noexcept {return std::move(this->integer_);}
|
||||
floating && as_floating (const std::nothrow_t&) && noexcept {return std::move(this->floating_);}
|
||||
string && as_string (const std::nothrow_t&) && noexcept {return std::move(this->string_);}
|
||||
offset_datetime&& as_offset_datetime(const std::nothrow_t&) && noexcept {return std::move(this->offset_datetime_);}
|
||||
local_datetime && as_local_datetime (const std::nothrow_t&) && noexcept {return std::move(this->local_datetime_);}
|
||||
local_date && as_local_date (const std::nothrow_t&) && noexcept {return std::move(this->local_date_);}
|
||||
local_time && as_local_time (const std::nothrow_t&) && noexcept {return std::move(this->local_time_);}
|
||||
array && as_array (const std::nothrow_t&) && noexcept {return std::move(this->array_.value());}
|
||||
table && as_table (const std::nothrow_t&) && noexcept {return std::move(this->table_.value());}
|
||||
|
||||
// ========================================================================
|
||||
// throw version
|
||||
// ------------------------------------------------------------------------
|
||||
// const reference
|
||||
|
||||
boolean const& as_boolean() const&
|
||||
{
|
||||
if(this->type_ != value_t::Boolean)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Boolean>(this->type_, *this);
|
||||
}
|
||||
return this->boolean_;
|
||||
}
|
||||
integer const& as_integer() const&
|
||||
{
|
||||
if(this->type_ != value_t::Integer)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Integer>(this->type_, *this);
|
||||
}
|
||||
return this->integer_;
|
||||
}
|
||||
floating const& as_floating() const&
|
||||
{
|
||||
if(this->type_ != value_t::Float)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
|
||||
}
|
||||
return this->floating_;
|
||||
}
|
||||
string const& as_string() const&
|
||||
{
|
||||
if(this->type_ != value_t::String)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::String>(this->type_, *this);
|
||||
}
|
||||
return this->string_;
|
||||
}
|
||||
offset_datetime const& as_offset_datetime() const&
|
||||
{
|
||||
if(this->type_ != value_t::OffsetDatetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::OffsetDatetime>(this->type_, *this);
|
||||
}
|
||||
return this->offset_datetime_;
|
||||
}
|
||||
local_datetime const& as_local_datetime() const&
|
||||
{
|
||||
if(this->type_ != value_t::LocalDatetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalDatetime>(this->type_, *this);
|
||||
}
|
||||
return this->local_datetime_;
|
||||
}
|
||||
local_date const& as_local_date() const&
|
||||
{
|
||||
if(this->type_ != value_t::LocalDate)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalDate>(this->type_, *this);
|
||||
}
|
||||
return this->local_date_;
|
||||
}
|
||||
local_time const& as_local_time() const&
|
||||
{
|
||||
if(this->type_ != value_t::LocalTime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalTime>(this->type_, *this);
|
||||
}
|
||||
return this->local_time_;
|
||||
}
|
||||
array const& as_array() const&
|
||||
{
|
||||
if(this->type_ != value_t::Array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Array>(this->type_, *this);
|
||||
}
|
||||
return this->array_.value();
|
||||
}
|
||||
table const& as_table() const&
|
||||
{
|
||||
if(this->type_ != value_t::Table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Table>(this->type_, *this);
|
||||
}
|
||||
return this->table_.value();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// nonconst reference
|
||||
|
||||
boolean & as_boolean() &
|
||||
{
|
||||
if(this->type_ != value_t::Boolean)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Boolean>(this->type_, *this);
|
||||
}
|
||||
return this->boolean_;
|
||||
}
|
||||
integer & as_integer() &
|
||||
{
|
||||
if(this->type_ != value_t::Integer)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Integer>(this->type_, *this);
|
||||
}
|
||||
return this->integer_;
|
||||
}
|
||||
floating & as_floating() &
|
||||
{
|
||||
if(this->type_ != value_t::Float)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
|
||||
}
|
||||
return this->floating_;
|
||||
}
|
||||
string & as_string() &
|
||||
{
|
||||
if(this->type_ != value_t::String)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::String>(this->type_, *this);
|
||||
}
|
||||
return this->string_;
|
||||
}
|
||||
offset_datetime & as_offset_datetime() &
|
||||
{
|
||||
if(this->type_ != value_t::OffsetDatetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::OffsetDatetime>(this->type_, *this);
|
||||
}
|
||||
return this->offset_datetime_;
|
||||
}
|
||||
local_datetime & as_local_datetime() &
|
||||
{
|
||||
if(this->type_ != value_t::LocalDatetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalDatetime>(this->type_, *this);
|
||||
}
|
||||
return this->local_datetime_;
|
||||
}
|
||||
local_date & as_local_date() &
|
||||
{
|
||||
if(this->type_ != value_t::LocalDate)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalDate>(this->type_, *this);
|
||||
}
|
||||
return this->local_date_;
|
||||
}
|
||||
local_time & as_local_time() &
|
||||
{
|
||||
if(this->type_ != value_t::LocalTime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalTime>(this->type_, *this);
|
||||
}
|
||||
return this->local_time_;
|
||||
}
|
||||
array & as_array() &
|
||||
{
|
||||
if(this->type_ != value_t::Array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Array>(this->type_, *this);
|
||||
}
|
||||
return this->array_.value();
|
||||
}
|
||||
table & as_table() &
|
||||
{
|
||||
if(this->type_ != value_t::Table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Table>(this->type_, *this);
|
||||
}
|
||||
return this->table_.value();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// rvalue reference
|
||||
|
||||
boolean && as_boolean() &&
|
||||
{
|
||||
if(this->type_ != value_t::Boolean)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Boolean>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->boolean_);
|
||||
}
|
||||
integer && as_integer() &&
|
||||
{
|
||||
if(this->type_ != value_t::Integer)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Integer>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->integer_);
|
||||
}
|
||||
floating && as_floating() &&
|
||||
{
|
||||
if(this->type_ != value_t::Float)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->floating_);
|
||||
}
|
||||
string && as_string() &&
|
||||
{
|
||||
if(this->type_ != value_t::String)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::String>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->string_);
|
||||
}
|
||||
offset_datetime && as_offset_datetime() &&
|
||||
{
|
||||
if(this->type_ != value_t::OffsetDatetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::OffsetDatetime>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->offset_datetime_);
|
||||
}
|
||||
local_datetime && as_local_datetime() &&
|
||||
{
|
||||
if(this->type_ != value_t::LocalDatetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalDatetime>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->local_datetime_);
|
||||
}
|
||||
local_date && as_local_date() &&
|
||||
{
|
||||
if(this->type_ != value_t::LocalDate)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalDate>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->local_date_);
|
||||
}
|
||||
local_time && as_local_time() &&
|
||||
{
|
||||
if(this->type_ != value_t::LocalTime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::LocalTime>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->local_time_);
|
||||
}
|
||||
array && as_array() &&
|
||||
{
|
||||
if(this->type_ != value_t::Array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Array>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->array_.value());
|
||||
}
|
||||
table && as_table() &&
|
||||
{
|
||||
if(this->type_ != value_t::Table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Table>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->table_.value());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// as|is_float (deprecated)
|
||||
|
||||
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
|
||||
bool is_float() const noexcept {return this->is(value_t::Float);}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// nothrow version
|
||||
|
||||
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating(std::nothrow) instead.")
|
||||
floating& as_float(const std::nothrow_t&) & noexcept
|
||||
{
|
||||
return this->floating_;
|
||||
}
|
||||
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating(std::nothrow) instead.")
|
||||
floating&& as_float(const std::nothrow_t&) && noexcept
|
||||
{
|
||||
return std::move(this->floating_);
|
||||
}
|
||||
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating(std::nothrow) instead.")
|
||||
floating const& as_float(const std::nothrow_t&) const& noexcept
|
||||
{
|
||||
return this->floating_;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// throw version
|
||||
|
||||
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
|
||||
floating& as_float() &
|
||||
{
|
||||
if(this->type_ != value_t::Float)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
|
||||
}
|
||||
return this->floating_;
|
||||
}
|
||||
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
|
||||
floating&& as_float() &&
|
||||
{
|
||||
if(this->type_ != value_t::Float)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->floating_);
|
||||
}
|
||||
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
|
||||
floating const& as_float() const&
|
||||
{
|
||||
if(this->type_ != value_t::Float)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
|
||||
}
|
||||
return this->floating_;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
std::string comment() const
|
||||
{
|
||||
return this->region_info_->comment();
|
||||
}
|
||||
std::string comment_before() const
|
||||
{
|
||||
return this->region_info_->comment_before();
|
||||
}
|
||||
std::string comment_inline() const
|
||||
{
|
||||
return this->region_info_->comment_inline();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void cleanup() noexcept
|
||||
@@ -626,9 +1024,6 @@ class value
|
||||
template<typename Region>
|
||||
friend void detail::change_region(value&, Region&&);
|
||||
|
||||
template<value_t T>
|
||||
struct switch_cast;
|
||||
|
||||
private:
|
||||
|
||||
using array_storage = detail::storage<array>;
|
||||
@@ -674,137 +1069,159 @@ void change_region(value& v, Region&& reg)
|
||||
return;
|
||||
}
|
||||
|
||||
template<value_t T>
|
||||
struct switch_cast;
|
||||
template<>
|
||||
struct switch_cast<value_t::Boolean>
|
||||
{
|
||||
static ::toml::boolean& invoke(value& v) {return v.as_boolean();}
|
||||
static ::toml::boolean const& invoke(value const& v) {return v.as_boolean();}
|
||||
static ::toml::boolean&& invoke(value&& v) {return std::move(v).as_boolean();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::Integer>
|
||||
{
|
||||
static ::toml::integer& invoke(value& v) {return v.as_integer();}
|
||||
static ::toml::integer const& invoke(value const& v) {return v.as_integer();}
|
||||
static ::toml::integer&& invoke(value&& v) {return std::move(v).as_integer();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::Float>
|
||||
{
|
||||
static ::toml::floating& invoke(value& v) {return v.as_floating();}
|
||||
static ::toml::floating const& invoke(value const& v) {return v.as_floating();}
|
||||
static ::toml::floating&& invoke(value&& v) {return std::move(v).as_floating();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::String>
|
||||
{
|
||||
static ::toml::string& invoke(value& v) {return v.as_string();}
|
||||
static ::toml::string const& invoke(value const& v) {return v.as_string();}
|
||||
static ::toml::string&& invoke(value&& v) {return std::move(v).as_string();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::OffsetDatetime>
|
||||
{
|
||||
static ::toml::offset_datetime& invoke(value& v) {return v.as_offset_datetime();}
|
||||
static ::toml::offset_datetime const& invoke(value const& v) {return v.as_offset_datetime();}
|
||||
static ::toml::offset_datetime&& invoke(value&& v) {return std::move(v).as_offset_datetime();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::LocalDatetime>
|
||||
{
|
||||
static ::toml::local_datetime& invoke(value& v) {return v.as_local_datetime();}
|
||||
static ::toml::local_datetime const& invoke(value const& v) {return v.as_local_datetime();}
|
||||
static ::toml::local_datetime&& invoke(value&& v) {return std::move(v).as_local_datetime();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::LocalDate>
|
||||
{
|
||||
static ::toml::local_date& invoke(value& v) {return v.as_local_date();}
|
||||
static ::toml::local_date const& invoke(value const& v) {return v.as_local_date();}
|
||||
static ::toml::local_date&& invoke(value&& v) {return std::move(v).as_local_date();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::LocalTime>
|
||||
{
|
||||
static ::toml::local_time& invoke(value& v) {return v.as_local_time();}
|
||||
static ::toml::local_time const& invoke(value const& v) {return v.as_local_time();}
|
||||
static ::toml::local_time&& invoke(value&& v) {return std::move(v).as_local_time();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::Array>
|
||||
{
|
||||
static ::toml::array& invoke(value& v) {return v.as_array();}
|
||||
static ::toml::array const& invoke(value const& v) {return v.as_array();}
|
||||
static ::toml::array&& invoke(value&& v) {return std::move(v).as_array();}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::Table>
|
||||
{
|
||||
static ::toml::table& invoke(value& v) {return v.as_table();}
|
||||
static ::toml::table const& invoke(value const& v) {return v.as_table();}
|
||||
static ::toml::table&& invoke(value&& v) {return std::move(v).as_table();}
|
||||
};
|
||||
}// detail
|
||||
|
||||
template<> struct value::switch_cast<value_t::Boolean>
|
||||
{
|
||||
static Boolean& invoke(value& v) {return v.boolean_;}
|
||||
static Boolean const& invoke(value const& v) {return v.boolean_;}
|
||||
static Boolean&& invoke(value&& v) {return std::move(v.boolean_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::Integer>
|
||||
{
|
||||
static Integer& invoke(value& v) {return v.integer_;}
|
||||
static Integer const& invoke(value const& v) {return v.integer_;}
|
||||
static Integer&& invoke(value&& v) {return std::move(v.integer_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::Float>
|
||||
{
|
||||
static Float& invoke(value& v) {return v.floating_;}
|
||||
static Float const& invoke(value const& v) {return v.floating_;}
|
||||
static Float&& invoke(value&& v) {return std::move(v.floating_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::String>
|
||||
{
|
||||
static String& invoke(value& v) {return v.string_;}
|
||||
static String const& invoke(value const& v) {return v.string_;}
|
||||
static String&& invoke(value&& v) {return std::move(v.string_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::OffsetDatetime>
|
||||
{
|
||||
static OffsetDatetime& invoke(value& v) {return v.offset_datetime_;}
|
||||
static OffsetDatetime const& invoke(value const& v) {return v.offset_datetime_;}
|
||||
static OffsetDatetime&& invoke(value&& v) {return std::move(v.offset_datetime_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::LocalDatetime>
|
||||
{
|
||||
static LocalDatetime& invoke(value& v) {return v.local_datetime_;}
|
||||
static LocalDatetime const& invoke(value const& v) {return v.local_datetime_;}
|
||||
static LocalDatetime&& invoke(value&& v) {return std::move(v.local_datetime_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::LocalDate>
|
||||
{
|
||||
static LocalDate& invoke(value& v) {return v.local_date_;}
|
||||
static LocalDate const& invoke(value const& v) {return v.local_date_;}
|
||||
static LocalDate&& invoke(value&& v) {return std::move(v.local_date_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::LocalTime>
|
||||
{
|
||||
static LocalTime& invoke(value& v) {return v.local_time_;}
|
||||
static LocalTime const& invoke(value const& v) {return v.local_time_;}
|
||||
static LocalTime&& invoke(value&& v) {return std::move(v.local_time_);}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::Array>
|
||||
{
|
||||
static Array& invoke(value& v) {return v.array_.value();}
|
||||
static Array const& invoke(value const& v) {return v.array_.value();}
|
||||
static Array&& invoke(value&& v) {return std::move(v.array_.value());}
|
||||
};
|
||||
template<> struct value::switch_cast<value_t::Table>
|
||||
{
|
||||
static Table& invoke(value& v) {return v.table_.value();}
|
||||
static Table const& invoke(value const& v) {return v.table_.value();}
|
||||
static Table&& invoke(value&& v) {return std::move(v.table_.value());}
|
||||
};
|
||||
|
||||
template<value_t T>
|
||||
typename detail::toml_default_type<T>::type& value::cast() &
|
||||
{
|
||||
if(T != this->type_)
|
||||
{
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the actual type is ", this->type_)}
|
||||
}));
|
||||
detail::throw_bad_cast<T>(this->type_, *this);
|
||||
}
|
||||
return switch_cast<T>::invoke(*this);
|
||||
return detail::switch_cast<T>::invoke(*this);
|
||||
}
|
||||
template<value_t T>
|
||||
typename detail::toml_default_type<T>::type const& value::cast() const&
|
||||
{
|
||||
if(T != this->type_)
|
||||
{
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the actual type is ", this->type_)}
|
||||
}));
|
||||
detail::throw_bad_cast<T>(this->type_, *this);
|
||||
}
|
||||
return switch_cast<T>::invoke(*this);
|
||||
return detail::switch_cast<T>::invoke(*this);
|
||||
}
|
||||
template<value_t T>
|
||||
typename detail::toml_default_type<T>::type&& value::cast() &&
|
||||
{
|
||||
if(T != this->type_)
|
||||
{
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the actual type is ", this->type_)}
|
||||
}));
|
||||
detail::throw_bad_cast<T>(this->type_, *this);
|
||||
}
|
||||
return switch_cast<T>::invoke(std::move(*this));
|
||||
return detail::switch_cast<T>::invoke(std::move(*this));
|
||||
}
|
||||
|
||||
bool operator==(const toml::value& lhs, const toml::value& rhs);
|
||||
bool operator< (const toml::value& lhs, const toml::value& rhs);
|
||||
|
||||
inline bool operator==(const toml::value& lhs, const toml::value& rhs)
|
||||
{
|
||||
if(lhs.type() != rhs.type()){return false;}
|
||||
switch(lhs.type())
|
||||
{
|
||||
case value_t::Boolean :
|
||||
return lhs.cast<value_t::Boolean >() == rhs.cast<value_t::Boolean >();
|
||||
{
|
||||
return lhs.as_boolean() == rhs.as_boolean();
|
||||
}
|
||||
case value_t::Integer :
|
||||
return lhs.cast<value_t::Integer >() == rhs.cast<value_t::Integer >();
|
||||
{
|
||||
return lhs.as_integer() == rhs.as_integer();
|
||||
}
|
||||
case value_t::Float :
|
||||
return lhs.cast<value_t::Float >() == rhs.cast<value_t::Float >();
|
||||
{
|
||||
return lhs.as_floating() == rhs.as_floating();
|
||||
}
|
||||
case value_t::String :
|
||||
return lhs.cast<value_t::String >() == rhs.cast<value_t::String >();
|
||||
{
|
||||
return lhs.as_string() == rhs.as_string();
|
||||
}
|
||||
case value_t::OffsetDatetime:
|
||||
return lhs.cast<value_t::OffsetDatetime>() == rhs.cast<value_t::OffsetDatetime>();
|
||||
{
|
||||
return lhs.as_offset_datetime() == rhs.as_offset_datetime();
|
||||
}
|
||||
case value_t::LocalDatetime:
|
||||
return lhs.cast<value_t::LocalDatetime>() == rhs.cast<value_t::LocalDatetime>();
|
||||
{
|
||||
return lhs.as_local_datetime() == rhs.as_local_datetime();
|
||||
}
|
||||
case value_t::LocalDate:
|
||||
return lhs.cast<value_t::LocalDate>() == rhs.cast<value_t::LocalDate>();
|
||||
{
|
||||
return lhs.as_local_date() == rhs.as_local_date();
|
||||
}
|
||||
case value_t::LocalTime:
|
||||
return lhs.cast<value_t::LocalTime>() == rhs.cast<value_t::LocalTime>();
|
||||
{
|
||||
return lhs.as_local_time() == rhs.as_local_time();
|
||||
}
|
||||
case value_t::Array :
|
||||
return lhs.cast<value_t::Array >() == rhs.cast<value_t::Array >();
|
||||
{
|
||||
return lhs.as_array() == rhs.as_array();
|
||||
}
|
||||
case value_t::Table :
|
||||
return lhs.cast<value_t::Table >() == rhs.cast<value_t::Table >();
|
||||
case value_t::Empty : return true;
|
||||
case value_t::Unknown : return false;
|
||||
default: return false;
|
||||
{
|
||||
return lhs.as_table() == rhs.as_table();
|
||||
}
|
||||
case value_t::Empty : {return true; }
|
||||
case value_t::Unknown : {return false;}
|
||||
default: {return false;}
|
||||
}
|
||||
}
|
||||
inline bool operator<(const toml::value& lhs, const toml::value& rhs)
|
||||
@@ -813,28 +1230,55 @@ inline bool operator<(const toml::value& lhs, const toml::value& rhs)
|
||||
switch(lhs.type())
|
||||
{
|
||||
case value_t::Boolean :
|
||||
return lhs.cast<value_t::Boolean >() < rhs.cast<value_t::Boolean >();
|
||||
{
|
||||
return lhs.as_boolean() < rhs.as_boolean();
|
||||
}
|
||||
case value_t::Integer :
|
||||
return lhs.cast<value_t::Integer >() < rhs.cast<value_t::Integer >();
|
||||
{
|
||||
return lhs.as_integer() < rhs.as_integer();
|
||||
}
|
||||
case value_t::Float :
|
||||
return lhs.cast<value_t::Float >() < rhs.cast<value_t::Float >();
|
||||
{
|
||||
return lhs.as_floating() < rhs.as_floating();
|
||||
}
|
||||
case value_t::String :
|
||||
return lhs.cast<value_t::String >() < rhs.cast<value_t::String >();
|
||||
{
|
||||
return lhs.as_string() < rhs.as_string();
|
||||
}
|
||||
case value_t::OffsetDatetime:
|
||||
return lhs.cast<value_t::OffsetDatetime>() < rhs.cast<value_t::OffsetDatetime>();
|
||||
{
|
||||
return lhs.as_offset_datetime() < rhs.as_offset_datetime();
|
||||
}
|
||||
case value_t::LocalDatetime:
|
||||
return lhs.cast<value_t::LocalDatetime>() < rhs.cast<value_t::LocalDatetime>();
|
||||
{
|
||||
return lhs.as_local_datetime() < rhs.as_local_datetime();
|
||||
}
|
||||
case value_t::LocalDate:
|
||||
return lhs.cast<value_t::LocalDate>() < rhs.cast<value_t::LocalDate>();
|
||||
{
|
||||
return lhs.as_local_date() < rhs.as_local_date();
|
||||
}
|
||||
case value_t::LocalTime:
|
||||
return lhs.cast<value_t::LocalTime>() < rhs.cast<value_t::LocalTime>();
|
||||
{
|
||||
return lhs.as_local_time() < rhs.as_local_time();
|
||||
}
|
||||
case value_t::Array :
|
||||
return lhs.cast<value_t::Array >() < rhs.cast<value_t::Array >();
|
||||
{
|
||||
return lhs.as_array() < rhs.as_array();
|
||||
}
|
||||
case value_t::Table :
|
||||
return lhs.cast<value_t::Table >() < rhs.cast<value_t::Table >();
|
||||
case value_t::Empty : return false;
|
||||
case value_t::Unknown : return false;
|
||||
default: return false;
|
||||
{
|
||||
// since unordered_map does not have `operator<` ...
|
||||
std::vector<std::pair<toml::key, toml::value>>
|
||||
L(lhs.as_table().begin(), lhs.as_table().end()),
|
||||
R(rhs.as_table().begin(), rhs.as_table().end());
|
||||
std::sort(L.begin(), L.end());
|
||||
std::sort(R.begin(), R.end());
|
||||
return std::lexicographical_compare(
|
||||
L.begin(), L.end(), R.begin(), R.end());
|
||||
}
|
||||
case value_t::Empty : {return false;}
|
||||
case value_t::Unknown : {return false;}
|
||||
default: {return false;}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,16 +1341,16 @@ visit(Visitor&& visitor, const toml::value& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::Boolean : {return visitor(v.cast<value_t::Boolean >());}
|
||||
case value_t::Integer : {return visitor(v.cast<value_t::Integer >());}
|
||||
case value_t::Float : {return visitor(v.cast<value_t::Float >());}
|
||||
case value_t::String : {return visitor(v.cast<value_t::String >());}
|
||||
case value_t::OffsetDatetime: {return visitor(v.cast<value_t::OffsetDatetime>());}
|
||||
case value_t::LocalDatetime : {return visitor(v.cast<value_t::LocalDatetime >());}
|
||||
case value_t::LocalDate : {return visitor(v.cast<value_t::LocalDate >());}
|
||||
case value_t::LocalTime : {return visitor(v.cast<value_t::LocalTime >());}
|
||||
case value_t::Array : {return visitor(v.cast<value_t::Array >());}
|
||||
case value_t::Table : {return visitor(v.cast<value_t::Table >());}
|
||||
case value_t::Boolean : {return visitor(v.as_boolean ());}
|
||||
case value_t::Integer : {return visitor(v.as_integer ());}
|
||||
case value_t::Float : {return visitor(v.as_floating ());}
|
||||
case value_t::String : {return visitor(v.as_string ());}
|
||||
case value_t::OffsetDatetime: {return visitor(v.as_offset_datetime());}
|
||||
case value_t::LocalDatetime : {return visitor(v.as_local_datetime ());}
|
||||
case value_t::LocalDate : {return visitor(v.as_local_date ());}
|
||||
case value_t::LocalTime : {return visitor(v.as_local_time ());}
|
||||
case value_t::Array : {return visitor(v.as_array ());}
|
||||
case value_t::Table : {return visitor(v.as_table ());}
|
||||
case value_t::Empty : break;
|
||||
case value_t::Unknown : break;
|
||||
default: break;
|
||||
@@ -921,16 +1365,16 @@ visit(Visitor&& visitor, toml::value& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::Boolean : {return visitor(v.cast<value_t::Boolean >());}
|
||||
case value_t::Integer : {return visitor(v.cast<value_t::Integer >());}
|
||||
case value_t::Float : {return visitor(v.cast<value_t::Float >());}
|
||||
case value_t::String : {return visitor(v.cast<value_t::String >());}
|
||||
case value_t::OffsetDatetime: {return visitor(v.cast<value_t::OffsetDatetime>());}
|
||||
case value_t::LocalDatetime : {return visitor(v.cast<value_t::LocalDatetime >());}
|
||||
case value_t::LocalDate : {return visitor(v.cast<value_t::LocalDate >());}
|
||||
case value_t::LocalTime : {return visitor(v.cast<value_t::LocalTime >());}
|
||||
case value_t::Array : {return visitor(v.cast<value_t::Array >());}
|
||||
case value_t::Table : {return visitor(v.cast<value_t::Table >());}
|
||||
case value_t::Boolean : {return visitor(v.as_boolean ());}
|
||||
case value_t::Integer : {return visitor(v.as_integer ());}
|
||||
case value_t::Float : {return visitor(v.as_floating ());}
|
||||
case value_t::String : {return visitor(v.as_string ());}
|
||||
case value_t::OffsetDatetime: {return visitor(v.as_offset_datetime());}
|
||||
case value_t::LocalDatetime : {return visitor(v.as_local_datetime ());}
|
||||
case value_t::LocalDate : {return visitor(v.as_local_date ());}
|
||||
case value_t::LocalTime : {return visitor(v.as_local_time ());}
|
||||
case value_t::Array : {return visitor(v.as_array ());}
|
||||
case value_t::Table : {return visitor(v.as_table ());}
|
||||
case value_t::Empty : break;
|
||||
case value_t::Unknown : break;
|
||||
default: break;
|
||||
@@ -945,16 +1389,16 @@ visit(Visitor&& visitor, toml::value&& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::Boolean : {return visitor(std::move(v.cast<value_t::Boolean >()));}
|
||||
case value_t::Integer : {return visitor(std::move(v.cast<value_t::Integer >()));}
|
||||
case value_t::Float : {return visitor(std::move(v.cast<value_t::Float >()));}
|
||||
case value_t::String : {return visitor(std::move(v.cast<value_t::String >()));}
|
||||
case value_t::OffsetDatetime: {return visitor(std::move(v.cast<value_t::OffsetDatetime>()));}
|
||||
case value_t::LocalDatetime : {return visitor(std::move(v.cast<value_t::LocalDatetime >()));}
|
||||
case value_t::LocalDate : {return visitor(std::move(v.cast<value_t::LocalDate >()));}
|
||||
case value_t::LocalTime : {return visitor(std::move(v.cast<value_t::LocalTime >()));}
|
||||
case value_t::Array : {return visitor(std::move(v.cast<value_t::Array >()));}
|
||||
case value_t::Table : {return visitor(std::move(v.cast<value_t::Table >()));}
|
||||
case value_t::Boolean : {return visitor(std::move(v.as_boolean ()));}
|
||||
case value_t::Integer : {return visitor(std::move(v.as_integer ()));}
|
||||
case value_t::Float : {return visitor(std::move(v.as_floating ()));}
|
||||
case value_t::String : {return visitor(std::move(v.as_string ()));}
|
||||
case value_t::OffsetDatetime: {return visitor(std::move(v.as_offset_datetime()));}
|
||||
case value_t::LocalDatetime : {return visitor(std::move(v.as_local_datetime ()));}
|
||||
case value_t::LocalDate : {return visitor(std::move(v.as_local_date ()));}
|
||||
case value_t::LocalTime : {return visitor(std::move(v.as_local_time ()));}
|
||||
case value_t::Array : {return visitor(std::move(v.as_array ()));}
|
||||
case value_t::Table : {return visitor(std::move(v.as_table ()));}
|
||||
case value_t::Empty : break;
|
||||
case value_t::Unknown : break;
|
||||
default: break;
|
||||
|
||||
Reference in New Issue
Block a user