Compare commits

..

19 Commits

Author SHA1 Message Date
ToruNiina
0df1dd6fea refactor: remove extraneous whitespaces 2024-07-04 02:57:22 +09:00
ToruNiina
a9fb557d70 feat: add error_kind to error_infos 2024-07-04 02:56:52 +09:00
ToruNiina
746abd73db feat: enable to get error_kind from error_info
and add serialization_error for future update
2024-07-04 02:55:47 +09:00
ToruNiina
7a6cb02293 feat: add error_kind to distinguish error_info 2024-07-04 00:57:50 +09:00
ToruNiina
00d6124f59 Merge branch 'v4_1_0' into try-get 2024-07-03 01:59:52 +09:00
ToruNiina
3a14cb5083 Merge branch 'main' into v4_1_0 2024-07-03 01:59:11 +09:00
ToruNiina
dc562ae5cb refactor: remove name of unused arg in func 2024-06-28 00:48:20 +09:00
ToruNiina
83f37a18b1 fix: incorrect function argument 2024-06-28 00:48:06 +09:00
ToruNiina
dc7e443be4 test: add try_get/find 2024-06-28 00:47:37 +09:00
ToruNiina
59921c1eb7 feat: add try_find 2024-06-28 00:19:00 +09:00
ToruNiina
a4d0189df3 refactor: move key_cast to utility 2024-06-28 00:18:46 +09:00
ToruNiina
3320d25abb feat: add try_get 2024-06-28 00:13:07 +09:00
ToruNiina
8efb305e8b feat: add try_from to return result<T, E> 2024-06-28 00:09:29 +09:00
ToruNiina
2baa47ef3d Merge branch 'main' into v4_1_0 2024-06-28 00:08:44 +09:00
ToruNiina
a0ae1a6bfd fix: access members directly 2024-06-26 22:42:32 +09:00
ToruNiina
044a66210d doc: add reference about try_at 2024-06-26 00:34:54 +09:00
ToruNiina
c4fb41b812 doc: add try_at to docs/features 2024-06-26 00:24:25 +09:00
ToruNiina
a610e75df0 test: add test of try_at for array and table 2024-06-26 00:09:08 +09:00
ToruNiina
0e84d0591b feat: add toml::basic_value::try_at 2024-06-25 23:50:28 +09:00
30 changed files with 2826 additions and 634 deletions

View File

@@ -14,13 +14,11 @@ string(REGEX REPLACE "#define TOML11_VERSION_PATCH ([0-9]+)" "\\1" TOML11_VERSIO
project(toml11 LANGUAGES CXX VERSION "${TOML11_VERSION_MAJOR}.${TOML11_VERSION_MINOR}.${TOML11_VERSION_PATCH}")
include(CTest) # to use ${BUILD_TESTING}
include(CMakeDependentOption)
include(CTest)
option(TOML11_PRECOMPILE "precompile toml11 library" OFF)
include(CMakeDependentOption)
cmake_policy(PUSH)
cmake_policy(SET CMP0127 OLD) # syntax of condition changed in 3.22
cmake_dependent_option(TOML11_INSTALL "install toml11 library" ON
"${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}" OFF)
cmake_dependent_option(TOML11_BUILD_EXAMPLES "build toml11 examples" OFF
@@ -29,8 +27,6 @@ cmake_dependent_option(TOML11_BUILD_TESTS "build toml11 unit tests" OFF
"${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}; ${BUILD_TESTING}" OFF)
cmake_dependent_option(TOML11_BUILD_TOML_TESTS "build toml11 toml-test encoder & decoder" OFF
"${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}" OFF)
cmake_policy(POP)
cmake_dependent_option(TOML11_TEST_WITH_ASAN "build toml11 unit tests with asan" OFF
"${TOML11_BUILD_TESTS}" OFF)
cmake_dependent_option(TOML11_TEST_WITH_UBSAN "build toml11 unit tests with ubsan" OFF
@@ -40,22 +36,8 @@ if(${TOML11_TEST_WITH_ASAN} AND ${TOML11_TEST_WITH_UBSAN})
message(FATAL_ERROR "trying to build tests with BOTH asan and ubsan")
endif()
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-Wall" TOML11_COMPILER_SUPPORTS_WALL)
check_cxx_compiler_flag("-Wextra" TOML11_COMPILER_SUPPORTS_WEXTRA)
check_cxx_compiler_flag("-Wpedantic" TOML11_COMPILER_SUPPORTS_WPEDANTIC)
check_cxx_compiler_flag("-Werror" TOML11_COMPILER_SUPPORTS_WERROR)
check_cxx_compiler_flag("-Wsign-conversion" TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION)
check_cxx_compiler_flag("-Wconversion" TOML11_COMPILER_SUPPORTS_WCONVERSION)
check_cxx_compiler_flag("-Wduplicated-cond" TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND)
check_cxx_compiler_flag("-Wduplicated-branches" TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
check_cxx_compiler_flag("-Wlogical-op" TOML11_COMPILER_SUPPORTS_WLOGICAL_OP)
check_cxx_compiler_flag("-Wdouble-promotion" TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
check_cxx_compiler_flag("-Wrange-loop-analysis" TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
check_cxx_compiler_flag("-Wundef" TOML11_COMPILER_SUPPORTS_WUNDEF)
check_cxx_compiler_flag("-Wshadow" TOML11_COMPILER_SUPPORTS_WSHADOW)
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)

175
README.md
View File

@@ -100,23 +100,6 @@ Copy `single_include/toml.hpp` to your preferred location and add it to your inc
By adding toml11 as a subdirectory using `git submodule` (or any other way),
you can either add `toml11/include` to your include path or use `add_subdirectory(toml11)` in your CMake project.
### CMake `FetchContent`
Using `FetchContent`, you can automatically download it.
```cmake
include(FetchContent)
FetchContent_Declare(
toml11
GIT_REPOSITORY https://github.com/ToruNiina/toml11.git
GIT_TAG v4.0.3
)
FetchContent_MakeAvailable(toml11)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE toml11::toml11)
```
### Install Using CMake
You can install toml11 using CMake with the following steps:
@@ -192,30 +175,8 @@ To parse a string directly, use `toml::parse_str`.
const toml::value input = toml::parse_str("a = 42");
```
When parsing string literals, you can use the `""_toml` literal.
```cpp
using namespace toml::literals::toml_literals;
const toml::value lit = "a = 42"_toml;
```
`toml::parse`, `parse_str` and `_toml` literal throw a `toml::syntax_error` exception in case of a syntax error.
The error message obtained with `what()` will look like this:
```
[error] bad integer: `_` must be surrounded by digits
--> internal string at line 64 in file main.cpp
|
1 | a = 123__456
| ^-- invalid underscore
Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755
Hint: invalid: _42, 1__000, 0123
```
Error messages can also be colorized by calling `toml::color::enable()`.
By using `toml::try_parse`, you can receive a `toml::result<toml::value, std::vector<toml::error_info>>` without throwing exceptions.
`toml::parse` throws a `toml::syntax_error` exception on syntax errors.
To avoid this, use `toml::try_parse`, which returns a `toml::result`.
```cpp
const auto input = toml::try_parse("input.toml");
@@ -266,40 +227,6 @@ const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a") << std::endl;
```
If type conversion or value lookup fails, a `toml::type_error` is thrown. The error message will look like this:
```
[error] toml::value::as_string(): bad_cast to string
--> input.toml
|
1 | a = 123_456
| ^^^^^^^-- the actual type is integer
```
You can access nested tables or arrays of tables in the same way.
```cpp
// [a]
// b = [
// {c = 42},
// {c = 54}
// ]
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a", "b", 1, "c") << std::endl;
```
Most STL containers and those with similar interfaces can be converted.
```cpp
// array = [3,1,4,1,5]
const toml::value input = toml::parse("input.toml");
const auto a1 = toml::find<std::vector<int>>(input, "array");
const auto a2 = toml::find<std::array<int, 5>>(input, "array");
const auto a3 = toml::find<std::deque<int>>(input, "array");
const auto a4 = toml::find<boost::container::small_vector<int, 8>>(input, "array");
```
You can perform advanced type conversions on complex TOML values.
```toml
@@ -318,36 +245,6 @@ const auto mixed = toml::find<
>(input, "mixed_array") << std::endl;
```
User-defined types can also be converted by using macros or defining some specific functions.
```cpp
namespace extlib
{
struct foo
{
int a;
std::string b;
};
} // extlib
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib::foo, a, b)
// ...
const auto input = R"(
[foo]
a = 42
b = "bar"
)"_toml;
const extlib::foo f = toml::find<extlib::foo>(input, "foo");
```
Using `toml::find_or`, you can get a default value in case of failure.
```cpp
const toml::value input = toml::parse("input.toml");
std::cout << toml::find_or(input, "a", 6*9) << std::endl;
```
For more details, please refer to the [documentation](https://toruniina.github.io/toml11/docs/features/value/).
### comments
@@ -434,72 +331,19 @@ std::cout << toml::format(input) << std::endl;
```cpp
toml::value output(toml::table{ {"a", 0xDEADBEEF} });
output.at("a").as_integer_fmt().fmt = toml::integer_format::hex;
output.at("a").as_integer_fmt().spacer = 4; // position of `_`
output.at("a").as_integer_fmt().spacer = 4;
std::cout << toml::format(input) << std::endl;
// a = 0xdead_beef
```
You can also specify the formatting for tables and arrays.
```cpp
toml::value output(toml::table{
{"array-of-tables", toml::array{}},
{"subtable", toml::table{}},
});
auto& aot = output.at("array-of-tables");
aot.as_array_fmt().fmt = toml::array_format::multiline; // one element per line
aot.as_array_fmt().body_indent = 4;
aot.as_array_fmt().closing_indent = 2;
toml::value v1(toml::table{ {"a", 42}, {"b", 3.14} });
v1.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v1));
toml::value v2(toml::table{ {"a", 42}, {"b", 3.14} });
v2.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v2));
output.at("subtable").as_table_fmt().fmt = toml::table_format::dotted;
output.at("subtable")["a"] = 42;
output.at("subtable")["b"] = 3.14;
std::cout << toml::format(output) << std::endl;
// subtable.b = 3.14
// subtable.a = 42
// array-of-tables = [
// {b = 3.14, a = 42},
// {b = 3.14, a = 42},
// ]
```
These settings are read during parsing and will be maintained as long as the value type does not change when modified.
For details on possible formatting specifications, please refer to the [documentation](https://toruniina.github.io/toml11/docs/features/serialize/).
### Configuring Types
### configuring types
Many types held by `toml::value`, such as `integer_type` and `array_type`, can be modified by changing the `type_config` type.
[The examples directory](https://github.com/ToruNiina/toml11/tree/main/examples) provides usage examples, such as using
arbitrary-precision integers, normalizing Unicode, and integrating with an external reflection library.
Refer to the [`examples` directory](https://github.com/ToruNiina/toml11/tree/main/examples) for complex use cases such as using multi-precision integers, changing containers, and normalizing Unicode.
Use these examples as references for implementing such configurations.
## Examples
The [`examples`](https://github.com/ToruNiina/toml11/tree/main/examples) directory provides various implementation examples in addition to type configurations.
- [boost_container](https://github.com/ToruNiina/toml11/tree/main/examples/boost_container)
- This example shows how to use `boost::container` containers for `array_type` and `table_type`.
- [boost_multiprecision](https://github.com/ToruNiina/toml11/tree/main/examples/boost_multiprecision)
- This example demonstrates the use of `boost::multiprecision` multi-precision numeric types for `integer_type` and `floating_type`.
- [parse_file](https://github.com/ToruNiina/toml11/tree/main/examples/parse_file)
- This example includes type conversion implementations, covering slightly more complex cases. The corresponding TOML file is included.
- [reflect](https://github.com/ToruNiina/toml11/tree/main/examples/reflect)
- This example shows self-type conversion using boost-ext/reflect for user-defined types.
- [unicode](https://github.com/ToruNiina/toml11/tree/main/examples/unicode)
- This example demonstrates normalizing Unicode strings when searching for keys using uni-algo.
Please refer to these examples for implementation guidance in such scenarios.
## Changes from v3
@@ -623,11 +467,6 @@ I appreciate the help of the contributors who introduced the great feature to th
- Add fuzzing test based on ClusterFuzzLite
- Esonhugh Skyworship (@Esonhugh)
- Fix function signature of `strerror_r` on macos
- Alberto (@0X1A)
- Fix issues with CMake package configuration when used with vcpkg
- Egor Pugin (@egorpugin)
- Fix incorrect operator<<() argument type that gives build error
## Licensing terms

View File

@@ -97,23 +97,6 @@ toml11を使うには複数の方法があります。
git submoduleなどでサブディレクトリにすれば、`toml11/include`にインクルードパスを通すか、
`add_subdirectory(toml11)` とすることで使用できます。
### CMake `FetchContent`
CMakeの `FetchContent`を使用することで、`build`ディレクトリに自動でダウンロードすることができます。
```cmake
include(FetchContent)
FetchContent_Declare(
toml11
GIT_REPOSITORY https://github.com/ToruNiina/toml11.git
GIT_TAG v4.0.3
)
FetchContent_MakeAvailable(toml11)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE toml11::toml11)
```
### Install using CMake
以下の手順で、CMakeを使ってインストールすることができます。
@@ -156,7 +139,7 @@ $ cmake -B ./build/ -DTOML11_BUILD_EXAMPLES=ON
$ cmake --build ./build/
```
### Building Tests
### Building example
`-DTOML11_BUILD_TESTS=ON`とすることで、ユニットテストをコンパイルできます。
@@ -191,30 +174,8 @@ const toml::value input = toml::parse("input.toml");
const toml::value input = toml::parse_str("a = 42");
```
文字列リテラルをパースする際は、`""_toml`リテラルを使うことができます。
```cpp
using namespace toml::literals::toml_literals;
const toml::value lit = "a = 42"_toml;
```
`toml::parse``parse_str`は文法エラーの際に `toml::syntax_error` 例外を投げます。
`what()`で得られるエラーメッセージは以下のようになります。
```
[error] bad integer: `_` must be surrounded by digits
--> internal string at line 64 in file main.cpp
|
1 | a = 123__456
| ^-- invalid underscore
Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755
Hint: invalid: _42, 1__000, 0123
```
エラーメッセージには`toml::color::enable()`を呼ぶことで色を付けることも可能です。
`toml::try_parse`を使うことで、例外を投げずに `toml::result<toml::value, std::vector<toml::error_info>>` を受け取ることができます。
`toml::parse`は文法エラーの際に `toml::syntax_error` 例外を投げます。
これを避けるには、 `toml::result` を返す `toml::try_parse` を使います。
```cpp
const auto input = toml::try_parse("input.toml");
@@ -258,46 +219,11 @@ if(input.contains("a") && input.at("a").is_integer())
}
```
`toml::find` を使うことで、型変換と検索同時に行うことができます。
`toml::find` を使うことで、型変換と検索同時に行ます。
```cpp
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<std::string>(input, "a") << std::endl;
```
型変換や値の検索に失敗した場合は、`toml::type_error`が送出されます。
その場合のエラーメッセージは以下のようになります。
```
[error] toml::value::as_string(): bad_cast to string
--> input.toml
|
1 | a = 123_456
| ^^^^^^^-- the actual type is integer
```
ネストされたテーブルやテーブルの配列にも同じ方法でアクセスできます。
```cpp
// [a]
// b = [
// {c = 42},
// {c = 54}
// ]
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a", "b", 1, "c") << std::endl;
```
ほとんどのSTLコンテナや、同様のインターフェースを持つコンテナへ変換が可能です。
```cpp
// array = [3,1,4,1,5]
const toml::value input = toml::parse("input.toml");
const auto a1 = toml::find<std::vector<int> >(input, "array") << std::endl;
const auto a2 = toml::find<std::array<int, 5>>(input, "array") << std::endl;
const auto a3 = toml::find<std::deque<int> >(input, "array") << std::endl;
const auto a4 = toml::find<boost::container::small_vector<int, 8>>(input, "array") << std::endl;
std::cout << toml::find<int>(input, "a") << std::endl;
```
また、複雑なTOML値に対して、高度な型変換を行うことができます。
@@ -318,36 +244,6 @@ const auto mixed = toml::find<
>(input, "mixed_array") << std::endl;
```
マクロの使用または特定の関数を定義することで、ユーザー定義型にも変換が可能です。
```cpp
namespace extlib
{
struct foo
{
int a;
std::string b;
};
} // extlib
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib::foo, a, b)
// ...
const auto input = R"(
[foo]
a = 42
b = "bar"
)"_toml;
const extlib::foo f = toml::find<extlib::foo>(input, "foo");
```
`toml::find_or`を使うことで、失敗時にデフォルト値を得ることができます。
```cpp
const toml::value input = toml::parse("input.toml");
std::cout << toml::find_or(input, "a", 6*9) << std::endl;
```
詳細については[ドキュメント](https://toruniina.github.io/toml11/ja/docs/features/value/)を参照してください。
### comments
@@ -436,73 +332,18 @@ toml::value output(toml::table{ {"a", 0xDEADBEEF} });
output.at("a").as_integer_fmt().fmt = toml::integer_format::hex;
output.at("a").as_integer_fmt().spacer = 4;
std::cout << toml::format(output) << std::endl;
// a = 0xdead_beef
std::cout << toml::format(input) << std::endl;
```
テーブルや配列のフォーマットも指定が可能です。
```cpp
toml::value output(toml::table{
{"array-of-tables", toml::array{}},
{"subtable", toml::table{}},
});
auto& aot = output.at("array-of-tables");
aot.as_array_fmt().fmt = toml::array_format::multiline;
aot.as_array_fmt().body_indent = 4;
aot.as_array_fmt().closing_indent = 2;
toml::value v1(toml::table{ {"a", 42}, {"b", 3.14} });
v1.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v1));
toml::value v2(toml::table{ {"a", 42}, {"b", 3.14} });
v2.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v2));
output.at("subtable").as_table_fmt().fmt = toml::table_format::dotted;
output.at("subtable")["a"] = 42;
output.at("subtable")["b"] = 3.14;
std::cout << toml::format(output) << std::endl;
// subtable.b = 3.14
// subtable.a = 42
// array-of-tables = [
// {b = 3.14, a = 42},
// {b = 2.71, a = 54},
// ]
```
これらの設定はパース時に読み取られ、値を変更した際も型が変わらない限り維持されます。
どのような指定が可能かなどの詳細は[ドキュメント](https://toruniina.github.io/toml11/ja/docs/features/serialize/)を参照してください。
### configuring types
`toml::value`が持つ型の多く、`integer_type``array_type`などは`type_config`型を変更することで変更可能です。
[`examples`ディレクトリ](https://github.com/ToruNiina/toml11/tree/main/examples)には、
多倍長整数を使用する場合やコンテナを変更する場合、ユニコードを正規化する場合などの複雑な使用例を用意しています。
[`examples`ディレクトリ](https://github.com/ToruNiina/toml11/tree/main/examples)には、多倍長整数を使用する場合やユニコードを正規化する場合、
外部のリフレクションライブラリと連携する場合などの複雑な使用例を用意しています。
そのような状況での実装例として参照してください。
## Examples
[`examples`ディレクトリ](https://github.com/ToruNiina/toml11/tree/main/examples)では、
型の設定の他にも実装例を紹介しています。
- [boost_container](https://github.com/ToruNiina/toml11/tree/main/examples/boost_container)
- `array_type``table_type``boost::container`のコンテナを使う例です。
- [boost_multiprecision](https://github.com/ToruNiina/toml11/tree/main/examples/boost_multiprecision)
- `integer_type``floating_type``boost::multiprecision`の多倍長数値型を使う例です。
- [parse_file](https://github.com/ToruNiina/toml11/tree/main/examples/parse_file)
- 少し複雑な場合も含めた、型変換の実装例です。対応するTOMLファイルが同梱されています。
- [reflect](https://github.com/ToruNiina/toml11/tree/main/examples/reflect)
- boost-ext/reflectを用いたユーザー定義型との自型変換の例です。
- [unicode](https://github.com/ToruNiina/toml11/tree/main/examples/unicode)
- uni-algoを用いて、キーを検索する際にユニコード文字列を正規化する例です。
## Changes from v3
toml11 v3からは複数の破壊的変更が追加されています。
@@ -625,10 +466,6 @@ toml11 v3からは複数の破壊的変更が追加されています。
- Add fuzzing test based on ClusterFuzzLite
- Esonhugh Skyworship (@Esonhugh)
- Fix function signature of `strerror_r` on macos
- Alberto (@0X1A)
- Fix issues with CMake package configuration when used with vcpkg
- Egor Pugin (@egorpugin)
- Fix incorrect operator<<() argument type that gives build error
## Licensing terms

View File

@@ -4,10 +4,8 @@ environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
generator: Visual Studio 16 2019
systemver: 10.0.18362.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
generator: Visual Studio 17 2022
systemver: 10.0.22621.0
configuration:
- Release
@@ -21,7 +19,7 @@ install:
build_script:
- cd C:\toml11
- cmake -B build -G"%generator%" -DCMAKE_SYSTEM_VERSION="%systemver%" -A x64 -DCMAKE_CXX_STANDARD=11 -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=ON
- cmake -B build -G"%generator%" -A x64 -DCMAKE_CXX_STANDARD=11 -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=ON
- cmake --build build --config "%configuration%"
test_script:

View File

@@ -7,19 +7,19 @@ type = "docs"
日本語版は[こちら](/toml11/ja/)
## [Installation](docs/installation)
## [Installation]({{< relref "/installation" >}})
This section describes how to build and install toml11.
## [Features](docs/features)
## [Features]({{< relref "/features" >}})
This section describes how to use toml11's features with examples.
## [Reference](docs/reference)
## [Reference]({{< relref "/reference" >}})
This section details toml11 functions and classes.
## [ChangeLog](docs/changelog)
## [ChangeLog]({{< relref "/changelog" >}})
This section describes changes from release to release.

View File

@@ -92,6 +92,32 @@ std::cout << v.at(1);
If the stored type is not `array_type`, a `type_error` is thrown.
### `try_at(std::size_t i)`
Performs the same operation as `at(i)`, but instead of throwing an exception on failure, it always returns a [`toml::result<T&, error_info>`]({{<ref "docs/reference/result">}}). It does not throw an exception on failure.
```cpp
toml::value v(toml::array{1,2,3});
auto res1 = v.try_at(1);
assert(res1.is_ok());
std::cout << res1.unwrap() << std::endl;
auto res5 = v.try_at(5);
assert(res1.is_err());
std::cout << toml::format_error(res1.unwrap_err()) << std::endl;
```
Additionally, since this `toml::result` holds a reference, it is possible to update the value.
```cpp
toml::value v(toml::array{1,2,3});
auto res1 = v.try_at(1);
assert(res1.is_ok());
res1.unwrap() = 42;
```
#### `at(std::string key)`, `operator[](std::string key)`
These are equivalent to `as_table().at(key)` and `as_table()[key]`.
@@ -105,6 +131,32 @@ v["a"] = 42;
If the stored type is not `table_type`, a `type_error` is thrown.
### `try_at(std::string key)`
Performs the same operation as `at(key)`, but instead of throwing an exception on failure, it always returns a [`toml::result<T&, error_info>`]({{<ref "docs/reference/result">}}). It does not throw an exception on failure.
```cpp
toml::value v(toml::table{ {"a", 42}, {"b", "foo"} });
auto res_a = v.try_at("a");
assert(res_a.is_ok());
std::cout << res_a.unwrap() << std::endl;
auto res_c = v.try_at("c");
assert(res_c.is_err());
std::cout << toml::format_error(res_c.unwrap_err()) << std::endl;
```
Additionally, since this `toml::result` holds a reference, it is possible to update the value.
```cpp
toml::value v(toml::table{ {"a", 42}, {"b", "foo"} });
auto res_a = v.try_at("a");
assert(res_a.is_ok());
res_a.unwrap() = 6 * 9;
```
#### `size()`
Returns the length.

View File

@@ -585,6 +585,27 @@ Throws `std::out_of_range` if the `table` does not contain the specified element
-----
### `try_at(key)`
```cpp
result<std::reference_wrapper<value_type>, error_info> try_at(const key_type& key) noexcept;
result<std::reference_wrapper<const value_type>, error_info> try_at(const key_type& key) const noexcept;
```
#### Return Value
After casting the current `value` to a `table`, it returns the element specified by the `key`.
If successful, it returns a `reference_wrapper` holding a reference to that element.
If unsuccessful, it returns an `error_info` corresponding to `type_error` or `out_of_range`.
#### Exceptions
Does not throw.
-----
#### `operator[](key)`
```cpp
@@ -652,6 +673,26 @@ Throws `toml::type_error` if the stored value is not an `array`.
Throws `std::out_of_range` if the specified element does not exist in the `array`.
-----
### `try_at(idx)`
```cpp
result<std::reference_wrapper<value_type>, error_info> try_at(const std::size_t idx) noexcept;
result<std::reference_wrapper<const value_type>, error_info> try_at(const std::size_t idx) const noexcept;
```
#### Return Value
After casting the current `value` to an `array`, it returns the element specified by the `idx`.
If successful, it returns a `reference_wrapper` holding a reference to that element.
If unsuccessful, it returns an `error_info` corresponding to `type_error` or `out_of_range`.
#### Exceptions
Does not throw.
-----

View File

@@ -7,19 +7,19 @@ type = "docs"
English version is [here](../en/)
## [Installation](docs/installation)
## [Installation]({{< relref "/installation" >}})
toml11のインストール方法について説明します。
## [Features](docs/features)
## [Features]({{< relref "/features" >}})
toml11の機能と使い方を例に沿って説明します。
## [Reference](docs/reference)
## [Reference]({{< relref "/reference" >}})
toml11が持つ関数・クラスの詳細を説明します。
## [ChangeLog](docs/changelog)
## [ChangeLog]({{< relref "/changelog" >}})
v3系から、そしてリリースごとの変化を説明します。

View File

@@ -96,6 +96,32 @@ std::cout << v.at(1);
格納している型が `array_type` ではなかった場合、 `type_error` を送出します。
#### `try_at(std::size_t i)`
`at(i)`と同様の操作をしますが、失敗時に例外を投げる代わりに、常に[`toml::result<T&, error_info>`]({{<ref "docs/reference/result">}})を返します。失敗時に例外は投げません。
```cpp
toml::value v(toml::array{1,2,3});
auto res1 = v.try_at(1);
assert(res1.is_ok());
std::cout << res1.unwrap() << std::endl;
auto res5 = v.try_at(5);
assert(res1.is_err());
std::cout << toml::format_error(res1.unwrap_err()) << std::endl;
```
また、この`toml::result`は成功値として参照を持つので、値を更新することも可能です。
```cpp
toml::value v(toml::array{1,2,3});
auto res1 = v.try_at(1);
assert(res1.is_ok());
res1.unwrap() = 42;
```
#### `at(std::string key)`, `operator[](std::string key)`
`as_table().at(key)`, `as_table()[key]` と同等です。
@@ -111,6 +137,32 @@ v["a"] = 42;
格納している型が `table_type` ではなかった場合、 `type_error` を送出します。
#### `try_at(std::string key)`
`at(key)`と同様の操作をしますが、失敗時に例外を投げる代わりに、常に[`toml::result<T&, error_info>`]({{<ref "docs/reference/result">}})を返します。失敗時に例外は投げません。
```cpp
toml::value v(toml::table{ {"a", 42}, {"b", "foo"} });
auto res_a = v.try_at("a");
assert(res_a.is_ok());
std::cout << res_a.unwrap() << std::endl;
auto res_c = v.try_at("c");
assert(res_c.is_err());
std::cout << toml::format_error(res_c.unwrap_err()) << std::endl;
```
また、この`toml::result`は成功値として参照を持つので、値を更新することも可能です。
```cpp
toml::value v(toml::table{ {"a", 42}, {"b", "foo"} });
auto res_a = v.try_at("a");
assert(res_a.is_ok());
res_a.unwrap() = 6 * 9;
```
#### `size()`
長さを返します。

View File

@@ -583,6 +583,27 @@ value_type const& at(const key_type& key) const;
-----
### `try_at(key)`
```cpp
result<std::reference_wrapper<value_type>, error_info> try_at(const key_type& key) noexcept;
result<std::reference_wrapper<const value_type>, error_info> try_at(const key_type& key) const noexcept;
```
#### 戻り値
今の`value``table`にキャストしたあと、`key`によって指定される要素を返します。
成功した場合、その要素への参照を持つ`reference_wrapper`を返します。
失敗した場合、 `type_error` または `out_of_range` に対応する `error_info` を返します。
#### 例外
投げません。
-----
#### `operator[](key)`
```cpp
@@ -652,6 +673,27 @@ value_type const& at(const std::size_t idx) const;
-----
### `try_at(idx)`
```cpp
result<std::reference_wrapper<value_type>, error_info> try_at(const std::size_t idx) noexcept;
result<std::reference_wrapper<const value_type>, error_info> try_at(const std::size_t idx) const noexcept;
```
#### 戻り値
今の`value``array`にキャストしたあと、`idx`によって指定される要素を返します。
成功した場合、その要素への参照を持つ`reference_wrapper`を返します。
失敗した場合、 `type_error` または `out_of_range` に対応する `error_info` を返します。
#### 例外
投げません。
-----
### `operator[](idx)`
```cpp

View File

@@ -498,7 +498,7 @@ struct source_location
static source_location current() { return source_location{}; }
};
inline std::string to_string(const source_location&)
inline std::string to_string(const source_location& loc)
{
return std::string("");
}

View File

@@ -4,6 +4,7 @@
#include <algorithm>
#include "get.hpp"
#include "utility.hpp"
#include "value.hpp"
#if defined(TOML11_HAS_STRING_VIEW)
@@ -101,54 +102,7 @@ find(basic_value<TC>&& v, const std::size_t idx)
}
// --------------------------------------------------------------------------
// toml::find(toml::value, toml::key, Ts&& ... keys)
namespace detail
{
// It suppresses warnings by -Wsign-conversion when we pass integer literal
// to toml::find. integer literal `0` is deduced as an int, and will be
// converted to std::size_t. This causes sign-conversion.
template<typename TC>
std::size_t key_cast(const std::size_t& v) noexcept
{
return v;
}
template<typename TC, typename T>
cxx::enable_if_t<std::is_integral<cxx::remove_cvref_t<T>>::value, std::size_t>
key_cast(const T& v) noexcept
{
return static_cast<std::size_t>(v);
}
// for string-like (string, string literal, string_view)
template<typename TC>
typename basic_value<TC>::key_type const&
key_cast(const typename basic_value<TC>::key_type& v) noexcept
{
return v;
}
template<typename TC>
typename basic_value<TC>::key_type
key_cast(const typename basic_value<TC>::key_type::value_type* v)
{
return typename basic_value<TC>::key_type(v);
}
#if defined(TOML11_HAS_STRING_VIEW)
template<typename TC>
typename basic_value<TC>::key_type
key_cast(const std::string_view v)
{
return typename basic_value<TC>::key_type(v);
}
#endif // string_view
} // detail
// ----------------------------------------------------------------------------
// find(v, keys...)
// toml::find(toml::value, toml::key, Ts&& ... keys) w/o conversion
template<typename TC, typename K1, typename K2, typename ... Ks>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&

View File

@@ -7,7 +7,18 @@ namespace toml
template<typename T>
struct from;
// {
// static T from_toml(const toml::value& v)
// template<typename TC>
// static T from_toml(const toml::basic_value<TC>& v)
// {
// // User-defined conversions ...
// }
// };
template<typename T>
struct try_from;
// {
// template<typename TC>
// static result<T, error_info> try_from_toml(const toml::basic_value<TC>& v) noexcept
// {
// // User-defined conversions ...
// }

View File

@@ -7,19 +7,47 @@
namespace toml
{
enum class error_kind : std::uint8_t
{
runtime_error,
out_of_range,
type_error,
syntax_error,
file_io_error,
serialization_error
};
// error info returned from parser.
struct error_info
{
error_info(std::string t, source_location l, std::string m, std::string s = "")
: title_(std::move(t)), locations_{std::make_pair(std::move(l), std::move(m))},
: kind_(error_kind::runtime_error), title_(std::move(t)),
locations_{std::make_pair(std::move(l), std::move(m))},
suffix_(std::move(s))
{}
error_info(std::string t, std::vector<std::pair<source_location, std::string>> l,
std::string s = "")
: title_(std::move(t)), locations_(std::move(l)), suffix_(std::move(s))
: kind_(error_kind::runtime_error), title_(std::move(t)),
locations_(std::move(l)), suffix_(std::move(s))
{}
error_info(error_kind k, std::string t, source_location l, std::string m, std::string s = "")
: kind_(k), title_(std::move(t)),
locations_{std::make_pair(std::move(l), std::move(m))},
suffix_(std::move(s))
{}
error_info(error_kind k, std::string t,
std::vector<std::pair<source_location, std::string>> l,
std::string s = "")
: kind_(k), title_(std::move(t)),
locations_(std::move(l)), suffix_(std::move(s))
{}
error_kind& kind() noexcept {return kind_;}
error_kind kind() const noexcept {return kind_;}
std::string const& title() const noexcept {return title_;}
std::string & title() noexcept {return title_;}
@@ -36,6 +64,7 @@ struct error_info
private:
error_kind kind_;
std::string title_;
std::vector<std::pair<source_location, std::string>> locations_;
std::string suffix_; // hint or something like that
@@ -75,7 +104,14 @@ template<typename ... Ts>
error_info make_error_info(
std::string title, source_location loc, std::string msg, Ts&& ... tail)
{
error_info ei(std::move(title), std::move(loc), std::move(msg));
error_info ei(error_kind::runtime_error, std::move(title), std::move(loc), std::move(msg));
return detail::make_error_info_rec(ei, std::forward<Ts>(tail) ... );
}
template<typename ... Ts>
error_info make_error_info(error_kind k,
std::string title, source_location loc, std::string msg, Ts&& ... tail)
{
error_info ei(k, std::move(title), std::move(loc), std::move(msg));
return detail::make_error_info_rec(ei, std::forward<Ts>(tail) ... );
}

View File

@@ -3,7 +3,7 @@
#include "../location.hpp"
#include "../types.hpp"
#include "../version.hpp" // IWYU pragma: keep for TOML11_HAS_CHAR8_T
#include "../value.hpp"
namespace toml
{
@@ -21,6 +21,12 @@ inline namespace toml_literals
::toml::value operator"" _toml(const char* str, std::size_t len);
#if defined(__cpp_char8_t)
# if __cpp_char8_t >= 201811L
# define TOML11_HAS_CHAR8_T 1
# endif
#endif
#if defined(TOML11_HAS_CHAR8_T)
// value of u8"" literal has been changed from char to char8_t and char8_t is
// NOT compatible to char

View File

@@ -552,7 +552,6 @@ TOML11_INLINE either string(const spec& s)
TOML11_INLINE non_ascii_key_char::non_ascii_key_char(const spec& s) noexcept
{
assert(s.v1_1_0_allow_non_english_in_bare_keys);
(void)s; // for NDEBUG
}
TOML11_INLINE std::uint32_t non_ascii_key_char::read_utf8(location& loc) const

View File

@@ -84,7 +84,7 @@ error_info make_syntax_error(std::string title,
{
auto msg = std::string("expected ") + scanner.expected_chars(loc);
auto src = source_location(region(loc));
return make_error_info(
return make_error_info(error_kind::syntax_error,
std::move(title), std::move(src), std::move(msg), std::move(suffix));
}
@@ -116,8 +116,8 @@ parse_comment_line(location& loc, context<TC>& ctx)
loc.advance();
if(loc.current() == '\n') { /*skip LF*/ loc.advance(); break; }
}
return err(make_error_info("toml::parse_comment_line: "
"newline (LF / CRLF) or EOF is expected",
return err(make_error_info(error_kind::syntax_error,
"toml::parse_comment_line: newline (LF / CRLF) or EOF is expected",
source_location(region(loc)), "but got this",
"Hint: most of the control characters are not allowed in comments"));
}
@@ -383,7 +383,7 @@ parse_dec_integer(location& loc, const context<TC>& ctx)
if( ! sfx_reg.is_ok())
{
loc = first;
return err(make_error_info("toml::parse_dec_integer: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_dec_integer: "
"invalid suffix: should be `_ non-digit-graph (graph | _graph)`",
source_location(region(loc)), "here"));
}
@@ -433,7 +433,7 @@ parse_integer(location& loc, const context<TC>& ctx)
if(std::isdigit(prefix))
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_integer: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_integer: "
"leading zero in an decimal integer is not allowed",
std::move(src), "leading zero"));
}
@@ -526,7 +526,7 @@ parse_floating(location& loc, const context<TC>& ctx)
}
else
{
return err(make_error_info("toml::parse_floating: inf value found"
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: inf value found"
" but the current environment does not support inf. Please"
" make sure that the floating-point implementation conforms"
" IEEE 754/ISO 60559 international standard.",
@@ -542,7 +542,7 @@ parse_floating(location& loc, const context<TC>& ctx)
}
else
{
return err(make_error_info("toml::parse_floating: inf value found"
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: inf value found"
" but the current environment does not support inf. Please"
" make sure that the floating-point implementation conforms"
" IEEE 754/ISO 60559 international standard.",
@@ -562,7 +562,7 @@ parse_floating(location& loc, const context<TC>& ctx)
}
else
{
return err(make_error_info("toml::parse_floating: NaN value found"
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: NaN value found"
" but the current environment does not support NaN. Please"
" make sure that the floating-point implementation conforms"
" IEEE 754/ISO 60559 international standard.",
@@ -583,7 +583,7 @@ parse_floating(location& loc, const context<TC>& ctx)
}
else
{
return err(make_error_info("toml::parse_floating: NaN value found"
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: NaN value found"
" but the current environment does not support NaN. Please"
" make sure that the floating-point implementation conforms"
" IEEE 754/ISO 60559 international standard.",
@@ -648,7 +648,7 @@ parse_floating(location& loc, const context<TC>& ctx)
{
auto src = source_location(region(loc));
loc = first;
return err(make_error_info("toml::parse_floating: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
"invalid suffix: should be `_ non-digit-graph (graph | _graph)`",
std::move(src), "here"));
}
@@ -702,21 +702,21 @@ parse_local_date_only(location& loc, const context<TC>& ctx)
if(year_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_date: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: "
"failed to read year `" + str.substr(0, 4) + "`",
std::move(src), "here"));
}
if(month_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_date: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: "
"failed to read month `" + str.substr(5, 2) + "`",
std::move(src), "here"));
}
if(day_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_date: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: "
"failed to read day `" + str.substr(8, 2) + "`",
std::move(src), "here"));
}
@@ -751,7 +751,7 @@ parse_local_date_only(location& loc, const context<TC>& ctx)
if((month < 1 || 12 < month) || (day < 1 || max_day < day))
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_date: invalid date.",
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: invalid date.",
std::move(src), "month must be 01-12, day must be any of "
"01-28,29,30,31 depending on the month/year."));
}
@@ -822,14 +822,14 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
if(hour_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
"failed to read hour `" + str.substr(0, 2) + "`",
std::move(src), "here"));
}
if(minute_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
"failed to read minute `" + str.substr(3, 2) + "`",
std::move(src), "here"));
}
@@ -840,7 +840,7 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
if((hour < 0 || 24 <= hour) || (minute < 0 || 60 <= minute))
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: invalid time.",
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: invalid time.",
std::move(src), "hour must be 00-23, minute must be 00-59."));
}
@@ -866,7 +866,7 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
if(sec_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
"failed to read second `" + str.substr(6, 2) + "`",
std::move(src), "here"));
}
@@ -875,7 +875,7 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
if(sec < 0 || 60 < sec) // :60 is allowed
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: invalid time.",
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: invalid time.",
std::move(src), "second must be 00-60."));
}
@@ -905,21 +905,21 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
if(ms_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
"failed to read milliseconds `" + secfrac.substr(0, 3) + "`",
std::move(src), "here"));
}
if(us_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
"failed to read microseconds`" + str.substr(3, 3) + "`",
std::move(src), "here"));
}
if(ns_r.is_err())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_local_time: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
"failed to read nanoseconds`" + str.substr(6, 3) + "`",
std::move(src), "here"));
}
@@ -985,7 +985,7 @@ parse_local_datetime(location& loc, const context<TC>& ctx)
else
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_local_datetime: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_datetime: "
"expect date-time delimiter `T`, `t` or ` `(space).",
std::move(src), "here"));
}
@@ -1049,7 +1049,7 @@ parse_offset_datetime(location& loc, const context<TC>& ctx)
else
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_offset_datetime: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
"expect date-time delimiter `T` or ` `(space).", std::move(src), "here"
));
}
@@ -1090,13 +1090,13 @@ parse_offset_datetime(location& loc, const context<TC>& ctx)
if(hour_r.is_err())
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_offset_datetime: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
"Failed to read offset hour part", std::move(src), "here"));
}
if(minute_r.is_err())
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_offset_datetime: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
"Failed to read offset minute part", std::move(src), "here"));
}
const auto hour = hour_r.unwrap();
@@ -1119,7 +1119,7 @@ parse_offset_datetime(location& loc, const context<TC>& ctx)
if (offset.hour < -24 || 24 < offset.hour ||
offset.minute < -60 || 60 < offset.minute)
{
return err(make_error_info("toml::parse_offset_datetime: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
"too large offset: |hour| <= 24, |minute| <= 60",
source_location(region(first, loc)), "here"));
}
@@ -1181,7 +1181,7 @@ parse_utf8_codepoint(const region& reg)
if(0xD800 <= codepoint && codepoint <= 0xDFFF)
{
auto src = source_location(reg);
return err(make_error_info("toml::parse_utf8_codepoint: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_utf8_codepoint: "
"[0xD800, 0xDFFF] is not a valid UTF-8",
std::move(src), "here"));
}
@@ -1202,7 +1202,7 @@ parse_utf8_codepoint(const region& reg)
else // out of UTF-8 region
{
auto src = source_location(reg);
return err(make_error_info("toml::parse_utf8_codepoint: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_utf8_codepoint: "
"input codepoint is too large.",
std::move(src), "must be in range [0x00, 0x10FFFF]"));
}
@@ -1243,7 +1243,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
if( ! reg.is_ok())
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_escape_sequence: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
"invalid token found in UTF-8 codepoint \\xhh",
std::move(src), "here"));
}
@@ -1261,7 +1261,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
if( ! reg.is_ok())
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_escape_sequence: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
"invalid token found in UTF-8 codepoint \\uhhhh",
std::move(src), "here"));
}
@@ -1279,7 +1279,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
if( ! reg.is_ok())
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_escape_sequence: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
"invalid token found in UTF-8 codepoint \\Uhhhhhhhh",
std::move(src), "here"));
}
@@ -1304,7 +1304,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
}
escape_seqs += ", \\uhhhh, or \\Uhhhhhhhh";
return err(make_error_info("toml::parse_escape_sequence: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
"unknown escape sequence.", std::move(src), escape_seqs));
}
return ok(retval);
@@ -1612,7 +1612,7 @@ parse_string(location& loc, const context<TC>& ctx)
else
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_string: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_string: "
"not a string", std::move(src), "here"));
}
}
@@ -1624,7 +1624,7 @@ parse_null(location& loc, const context<TC>& ctx)
const auto& spec = ctx.toml_spec();
if( ! spec.ext_null_value)
{
return err(make_error_info("toml::parse_null: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_null: "
"invalid spec: spec.ext_null_value must be true.",
source_location(region(loc)), "here"));
}
@@ -1754,7 +1754,7 @@ parse_key(location& loc, const context<TC>& ctx)
if(keys.empty())
{
auto src = source_location(region(first));
return err(make_error_info("toml::parse_key: expected a new key, "
return err(make_error_info(error_kind::syntax_error, "toml::parse_key: expected a new key, "
"but got nothing", std::move(src), "reached EOF"));
}
@@ -1906,7 +1906,7 @@ parse_array(location& loc, context<TC>& ctx)
if(loc.eof() || loc.current() != '[')
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_array: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_array: "
"The next token is not an array", std::move(src), "here"));
}
loc.advance();
@@ -1940,7 +1940,7 @@ parse_array(location& loc, context<TC>& ctx)
if( ! comma_found)
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_array: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_array: "
"expected value-separator `,` or closing `]`",
std::move(src), "here"));
}
@@ -2033,7 +2033,7 @@ parse_array(location& loc, context<TC>& ctx)
if(loc.current() != ']')
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_array: missing closing bracket `]`",
return err(make_error_info(error_kind::syntax_error, "toml::parse_array: missing closing bracket `]`",
std::move(src), "expected `]`, reached EOF"));
}
else
@@ -2216,7 +2216,7 @@ insert_value(const inserting_value_kind kind,
if(fmt == table_format::oneline || fmt == table_format::multiline_oneline)
{
// foo = {bar = "baz"} or foo = { \n bar = "baz" \n }
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"failed to insert a value: inline table is immutable",
key_loc, "inserting this",
found->second.location(), "to this table"));
@@ -2224,7 +2224,7 @@ insert_value(const inserting_value_kind kind,
// dotted key cannot reopen a table.
if(kind ==inserting_value_kind::dotted_keys && fmt != table_format::dotted)
{
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"reopening a table using dotted keys",
key_loc, "dotted key cannot reopen a table",
found->second.location(), "this table is already closed"));
@@ -2237,7 +2237,7 @@ insert_value(const inserting_value_kind kind,
// aot = [{this = "type", of = "aot"}] # cannot be reopened
if(found->second.as_array_fmt().fmt != array_format::array_of_tables)
{
return err(make_error_info("toml::insert_value:"
return err(make_error_info(error_kind::syntax_error, "toml::insert_value:"
"inline array of tables are immutable",
key_loc, "inserting this",
found->second.location(), "inline array of tables"));
@@ -2249,7 +2249,7 @@ insert_value(const inserting_value_kind kind,
// [[array.of.tables]]
// [array.of] # reopening supertable is okay
// tables.x = "foo" # appending `x` to the first table
return err(make_error_info("toml::insert_value:"
return err(make_error_info(error_kind::syntax_error, "toml::insert_value:"
"dotted key cannot reopen an array-of-tables",
key_loc, "inserting this",
found->second.location(), "to this array-of-tables."));
@@ -2269,7 +2269,7 @@ insert_value(const inserting_value_kind kind,
}
else
{
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"failed to insert a value, value already exists",
key_loc, "while inserting this",
found->second.location(), "non-table value already exists"));
@@ -2283,7 +2283,7 @@ insert_value(const inserting_value_kind kind,
{
if(current_table.find(key) != current_table.end())
{
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"failed to insert a value, value already exists",
key_loc, "inserting this",
current_table.at(key).location(), "but value already exists"));
@@ -2307,7 +2307,7 @@ insert_value(const inserting_value_kind kind,
if( ! target.is_table() || // could be an array-of-tables
target.as_table_fmt().fmt != table_format::implicit)
{
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"failed to insert a table, table already defined",
key_loc, "inserting this",
target.location(), "this table is explicitly defined"));
@@ -2322,7 +2322,7 @@ insert_value(const inserting_value_kind kind,
// w = "foo"
// [x]
// y = "bar"
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"failed to insert a table, table keys conflict to each other",
key_loc, "inserting this table",
kv.second.location(), "having this value",
@@ -2362,14 +2362,14 @@ insert_value(const inserting_value_kind kind,
{
if( ! found->second.is_array_of_tables())
{
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"failed to insert an array of tables, value already exists",
key_loc, "while inserting this",
found->second.location(), "non-table value already exists"));
}
if(found->second.as_array_fmt().fmt != array_format::array_of_tables)
{
return err(make_error_info("toml::insert_value: "
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
"failed to insert a table, inline array of tables is immutable",
key_loc, "while inserting this",
found->second.location(), "this is inline array-of-tables"));
@@ -2383,7 +2383,7 @@ insert_value(const inserting_value_kind kind,
}
}
}
return err(make_error_info("toml::insert_key: no keys found",
return err(make_error_info(error_kind::syntax_error, "toml::insert_key: no keys found",
std::move(key_loc), "here"));
}
@@ -2403,7 +2403,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
if(loc.eof() || loc.current() != '{')
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_inline_table: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: "
"The next token is not an inline table", std::move(src), "here"));
}
loc.advance();
@@ -2438,7 +2438,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
if(comma_found && ! spec.v1_1_0_allow_trailing_comma_in_inline_tables)
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_inline_table: trailing "
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: trailing "
"comma is not allowed in TOML-v1.0.0)", std::move(src), "here"));
}
@@ -2458,7 +2458,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
if( ! comma_found && ! still_empty)
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_inline_table: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: "
"expected value-separator `,` or closing `}`",
std::move(src), "here"));
}
@@ -2586,7 +2586,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
if(loc.current() != '}')
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_inline_table: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: "
"missing closing bracket `}`",
std::move(src), "expected `}`, reached line end"));
}
@@ -2702,7 +2702,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
return ok(value_t::floating);
}
auto src = source_location(region(loc));
return err(make_error_info(
return err(make_error_info(error_kind::syntax_error,
"bad float: `_` must be surrounded by digits",
std::move(src), "invalid underscore",
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
@@ -2723,7 +2723,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
return ok(value_t::floating);
}
auto src = source_location(region(loc));
return err(make_error_info(
return err(make_error_info(error_kind::syntax_error,
"bad float: `_` must be surrounded by digits",
std::move(src), "invalid underscore",
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
@@ -2750,7 +2750,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
int_reg.as_string() == "-0" || int_reg.as_string() == "+0"))
{
auto src = source_location(region(loc));
return err(make_error_info(
return err(make_error_info(error_kind::syntax_error,
"bad integer: leading zero is not allowed in decimal int",
std::move(src), "leading zero",
"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
@@ -2759,7 +2759,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
else
{
auto src = source_location(region(loc));
return err(make_error_info(
return err(make_error_info(error_kind::syntax_error,
"bad integer: `_` must be surrounded by digits",
std::move(src), "invalid underscore",
"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
@@ -2771,7 +2771,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
if(loc.current() == '0')
{
loc.retrace();
return err(make_error_info(
return err(make_error_info(error_kind::syntax_error,
"bad integer: leading zero",
source_location(region(loc)), "leading zero is not allowed",
std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
@@ -2780,7 +2780,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
}
else // invalid digits, especially in oct/bin ints.
{
return err(make_error_info(
return err(make_error_info(error_kind::syntax_error,
"bad integer: invalid digit after an integer",
source_location(region(loc)), "this digit is not allowed",
std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
@@ -2791,7 +2791,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
if(c == ':' || c == '-')
{
auto src = source_location(region(loc));
return err(make_error_info("bad datetime: invalid format",
return err(make_error_info(error_kind::syntax_error, "bad datetime: invalid format",
std::move(src), "here",
std::string("Hint: valid : 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z\n"
"Hint: invalid: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30")
@@ -2800,7 +2800,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
if(c == '.' || c == 'e' || c == 'E')
{
auto src = source_location(region(loc));
return err(make_error_info("bad float: invalid format",
return err(make_error_info(error_kind::syntax_error, "bad float: invalid format",
std::move(src), "here", std::string(
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")));
@@ -2811,7 +2811,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
if( ! loc.eof() && loc.current() == '.')
{
auto src = source_location(region(loc));
return err(make_error_info("bad float: integer part is required before decimal point",
return err(make_error_info(error_kind::syntax_error, "bad float: integer part is required before decimal point",
std::move(src), "missing integer part", std::string(
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")
@@ -2820,7 +2820,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
if( ! loc.eof() && loc.current() == '_')
{
auto src = source_location(region(loc));
return err(make_error_info("bad number: `_` must be surrounded by digits",
return err(make_error_info(error_kind::syntax_error, "bad number: `_` must be surrounded by digits",
std::move(src), "digits required before `_`", std::string(
"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
"Hint: invalid: _42, 1__000, 0123\n")
@@ -2828,7 +2828,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
}
auto src = source_location(region(loc));
return err(make_error_info("bad format: unknown value appeared",
return err(make_error_info(error_kind::syntax_error, "bad format: unknown value appeared",
std::move(src), "here"));
}
@@ -2968,7 +2968,7 @@ parse_value(location& loc, context<TC>& ctx)
else
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_value: unknown value appeared",
return err(make_error_info(error_kind::syntax_error, "toml::parse_value: unknown value appeared",
std::move(src), "here"));
}
}
@@ -2985,7 +2985,7 @@ parse_value(location& loc, context<TC>& ctx)
default:
{
auto src = source_location(region(loc));
return err(make_error_info("toml::parse_value: unknown value appeared",
return err(make_error_info(error_kind::syntax_error, "toml::parse_value: unknown value appeared",
std::move(src), "here"));
}
}
@@ -3097,7 +3097,7 @@ parse_table(location& loc, context<TC>& ctx, basic_value<TC>& table)
newline_found = newline_found || (sp.has_value() && sp.value().newline_found);
if( ! newline_found)
{
return err(make_error_info("toml::parse_table: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_table: "
"newline (LF / CRLF) or EOF is expected",
source_location(region(loc)), "here"));
}
@@ -3560,7 +3560,8 @@ try_parse(std::string fname, spec s = spec::default_version())
if(!ifs.good())
{
std::vector<error_info> e;
e.push_back(error_info("toml::parse: Error opening file \"" + fname + "\"", {}));
e.push_back(error_info(error_kind::file_io_error,
"toml::parse: Error opening file \"" + fname + "\"", {}));
return err(std::move(e));
}
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
@@ -3641,7 +3642,8 @@ try_parse(const FSPATH& fpath, spec s = spec::default_version())
if(!ifs.good())
{
std::vector<error_info> e;
e.push_back(error_info("toml::parse: Error opening file \"" + fpath.string() + "\"", {}));
e.push_back(error_info(error_kind::file_io_error,
"toml::parse: Error opening file \"" + fpath.string() + "\"", {}));
return err(std::move(e));
}
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
@@ -3675,7 +3677,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
const long beg = std::ftell(fp);
if (beg == -1L)
{
return err(std::vector<error_info>{error_info(
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
std::string("Failed to access: \"") + filename +
"\", errno = " + std::to_string(errno), {}
)});
@@ -3684,7 +3686,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
const int res_seekend = std::fseek(fp, 0, SEEK_END);
if (res_seekend != 0)
{
return err(std::vector<error_info>{error_info(
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
std::string("Failed to seek: \"") + filename +
"\", errno = " + std::to_string(errno), {}
)});
@@ -3693,7 +3695,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
const long end = std::ftell(fp);
if (end == -1L)
{
return err(std::vector<error_info>{error_info(
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
std::string("Failed to access: \"") + filename +
"\", errno = " + std::to_string(errno), {}
)});
@@ -3704,7 +3706,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET);
if (res_seekbeg != 0)
{
return err(std::vector<error_info>{error_info(
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
std::string("Failed to seek: \"") + filename +
"\", errno = " + std::to_string(errno), {}
)});
@@ -3717,7 +3719,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
if(actual != static_cast<std::size_t>(fsize))
{
return err(std::vector<error_info>{error_info(
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
std::string("File size changed: \"") + filename +
std::string("\" make sure that FILE* is in binary mode "
"to avoid LF <-> CRLF conversion"), {}

View File

@@ -90,6 +90,13 @@ struct has_specialized_from_impl
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
static std::true_type check(::toml::from<T>*);
};
struct has_specialized_try_from_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::try_from<T>)>
static std::true_type check(::toml::try_from<T>*);
};
struct has_specialized_into_impl
{
template<typename T>
@@ -130,6 +137,8 @@ template<typename T>
struct has_specialized_from: decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_into: decltype(has_specialized_into_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_try_from: decltype(has_specialized_try_from_impl::check<T>(nullptr)){};
#ifdef __INTEL_COMPILER
#undef decltype

228
include/toml11/try_find.hpp Normal file
View File

@@ -0,0 +1,228 @@
#ifndef TOML11_TRY_FIND_HPP
#define TOML11_TRY_FIND_HPP
#include <algorithm>
#include "try_get.hpp"
#include "utility.hpp"
#include "value.hpp"
#if defined(TOML11_HAS_STRING_VIEW)
#include <string_view>
#endif
namespace toml
{
// ----------------------------------------------------------------------------
// find<T>(value, key);
template<typename T, typename TC>
decltype(try_get<T>(std::declval<basic_value<TC> const&>()))
try_find(const basic_value<TC>& v, const typename basic_value<TC>::key_type& ky) noexcept
{
const auto res = v.try_at(ky);
if(res.is_err())
{
return err(res.as_err());
}
return try_get<T>(res.as_ok());
}
template<typename T, typename TC>
decltype(try_get<T>(std::declval<basic_value<TC>&>()))
try_find(basic_value<TC>& v, const typename basic_value<TC>::key_type& ky) noexcept
{
auto res = v.try_at(ky);
if(res.is_err())
{
return err(res.as_err());
}
return try_get<T>(res.as_ok());
}
template<typename T, typename TC>
decltype(try_get<T>(std::declval<basic_value<TC>&&>()))
try_find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& ky) noexcept
{
auto res = v.try_at(ky);
if(res.is_err())
{
return err(res.as_err());
}
return try_get<T>(std::move(res.as_ok()));
}
// ----------------------------------------------------------------------------
// find<T>(value, idx)
template<typename T, typename TC>
decltype(try_get<T>(std::declval<basic_value<TC> const&>()))
try_find(const basic_value<TC>& v, const std::size_t idx) noexcept
{
const auto res = v.try_at(idx);
if(res.is_err())
{
return err(res.as_err());
}
return try_get<T>(res.as_ok());
}
template<typename T, typename TC>
decltype(try_get<T>(std::declval<basic_value<TC>&>()))
try_find(basic_value<TC>& v, const std::size_t idx) noexcept
{
auto res = v.try_at(idx);
if(res.is_err())
{
return err(res.as_err());
}
return try_get<T>(res.as_ok());
}
template<typename T, typename TC>
decltype(try_get<T>(std::declval<basic_value<TC>&&>()))
try_find(basic_value<TC>&& v, const std::size_t idx) noexcept
{
auto res = v.try_at(idx);
if(res.is_err())
{
return err(res.as_err());
}
return try_get<T>(std::move(res.as_ok()));
}
// ----------------------------------------------------------------------------
// find(value, key/idx), w/o conversion
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<std::reference_wrapper<basic_value<TC>>, error_info>>
try_find(basic_value<TC>& v, const typename basic_value<TC>::key_type& ky) noexcept
{
return v.try_at(ky);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<std::reference_wrapper<const basic_value<TC>>, error_info>>
try_find(basic_value<TC> const& v, const typename basic_value<TC>::key_type& ky) noexcept
{
return v.try_at(ky);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<basic_value<TC>, error_info>>
try_find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& ky) noexcept
{
auto res = v.try_at(ky);
if(res.is_err())
{
return err(res.as_err());
}
return ok(basic_value<TC>(std::move(res.as_ok())));
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<std::reference_wrapper<basic_value<TC>>, error_info>>
try_find(basic_value<TC>& v, const std::size_t idx) noexcept
{
return v.try_at(idx);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<std::reference_wrapper<const basic_value<TC>>, error_info>>
try_find(basic_value<TC> const& v, const std::size_t idx) noexcept
{
return v.try_at(idx);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<basic_value<TC>, error_info>>
try_find(basic_value<TC>&& v, const std::size_t idx) noexcept
{
auto res = v.try_at(idx);
if(res.is_err())
{
return err(std::move(res.as_err()));
}
return ok(basic_value<TC>(std::move(res.as_ok())));
}
// --------------------------------------------------------------------------
// toml::find(toml::value, toml::key, Ts&& ... keys) w/o conversion
template<typename TC, typename K1, typename K2, typename ... Ks>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<std::reference_wrapper<const basic_value<TC>>, error_info>>
try_find(const basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks) noexcept
{
auto res = v.try_at(detail::key_cast<TC>(k1));
if(res.is_err())
{
return err(res.as_err());
}
return try_find(res.as_ok(), detail::key_cast<TC>(k2), ks...);
}
template<typename TC, typename K1, typename K2, typename ... Ks>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<std::reference_wrapper<basic_value<TC>>, error_info>>
try_find(basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks) noexcept
{
auto res = v.try_at(detail::key_cast<TC>(k1));
if(res.is_err())
{
return err(res.as_err());
}
return try_find(res.as_ok(), detail::key_cast<TC>(k2), ks...);
}
template<typename TC, typename K1, typename K2, typename ... Ks>
cxx::enable_if_t<detail::is_type_config<TC>::value,
result<basic_value<TC>, error_info>>
try_find(basic_value<TC>&& v, const K1& k1, const K2& k2, const Ks& ... ks) noexcept
{
auto res = v.try_at(detail::key_cast<TC>(k1));
if(res.is_err())
{
return err(res.as_err());
}
return try_find(std::move(res.as_ok()), detail::key_cast<TC>(k2), ks...);
}
// ----------------------------------------------------------------------------
// find<T>(v, keys...)
template<typename T, typename TC, typename K1, typename K2, typename ... Ks>
decltype(::toml::try_get<T>(std::declval<const basic_value<TC>&>()))
try_find(const basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks) noexcept
{
auto res = v.try_at(detail::key_cast<TC>(k1));
if(res.is_err())
{
return err(res.as_err());
}
return try_find<T>(res.as_ok(), detail::key_cast<TC>(k2), ks...);
}
template<typename T, typename TC, typename K1, typename K2, typename ... Ks>
decltype(::toml::try_get<T>(std::declval<basic_value<TC>&>()))
try_find(basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks) noexcept
{
auto res = v.try_at(detail::key_cast<TC>(k1));
if(res.is_err())
{
return err(res.as_err());
}
return try_find<T>(res.as_ok(), detail::key_cast<TC>(k2), ks...);
}
template<typename T, typename TC, typename K1, typename K2, typename ... Ks>
decltype(::toml::try_get<T>(std::declval<basic_value<TC>&&>()))
try_find(basic_value<TC>&& v, const K1& k1, const K2& k2, const Ks& ... ks) noexcept
{
auto res = v.try_at(detail::key_cast<TC>(k1));
if(res.is_err())
{
return err(res.as_err());
}
return try_find<T>(std::move(res.as_ok()), detail::key_cast<TC>(k2), ks...);
}
} // toml
#endif // TOML11_FIND_HPP

473
include/toml11/try_get.hpp Normal file
View File

@@ -0,0 +1,473 @@
#ifndef TOML11_TRY_GET_HPP
#define TOML11_TRY_GET_HPP
#include <algorithm>
#include "error_info.hpp"
#include "from.hpp"
#include "types.hpp"
#include "value.hpp"
#if defined(TOML11_HAS_STRING_VIEW)
#include <string_view>
#endif // string_view
namespace toml
{
// ============================================================================
// T is toml::value; identity transformation.
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value,
result<std::reference_wrapper<T>, error_info>>
try_get(basic_value<TC>& v) noexcept
{
return ok(std::ref(v));
}
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value,
result<std::reference_wrapper<const T>, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
return ok(std::cref(v));
}
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value,
result<T, error_info>>
try_get(basic_value<TC>&& v) noexcept
{
return ok(basic_value<TC>(std::move(v)));
}
// ============================================================================
// exact toml::* type
template<typename T, typename TC>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value,
result<std::reference_wrapper<T>, error_info>>
try_get(basic_value<TC>& v) noexcept
{
constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;
if(v.type() == ty)
{
return ok(std::ref(detail::getter<TC, ty>::get_nothrow(v)));
}
else
{
return err(detail::make_type_error(v, "toml::try_get()", ty));
}
}
template<typename T, typename TC>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value,
result<std::reference_wrapper<const T>, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;
if(v.type() == ty)
{
return ok(std::cref(detail::getter<TC, ty>::get_nothrow(v)));
}
else
{
return err(detail::make_type_error(v, "toml::try_get()", ty));
}
}
template<typename T, typename TC>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value,
result<T, error_info>>
try_get(basic_value<TC>&& v) noexcept
{
constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;
if(v.type() == ty)
{
return ok(detail::getter<TC, ty>::get_nothrow(std::move(v)));
}
else
{
return err(detail::make_type_error(v, "toml::try_get()", ty));
}
}
// ============================================================================
// T is toml::basic_value<U>
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_basic_value<T>,
cxx::negation<std::is_same<T, basic_value<TC>>>
>::value, result<T, error_info>>
try_get(basic_value<TC> v) noexcept
{
return ok(T(std::move(v)));
}
// ============================================================================
// integer convertible from toml::value::integer_type
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
std::is_integral<T>,
cxx::negation<std::is_same<T, bool>>,
detail::is_not_toml_type<T, basic_value<TC>>,
cxx::negation<detail::has_from_toml_method<T, TC>>,
cxx::negation<detail::has_specialized_from<T>>
>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.is_integer())
{
return ok(static_cast<T>(v.as_integer(std::nothrow)));
}
else
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::integer));
}
}
// ============================================================================
// floating point convertible from toml::value::floating_type
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
std::is_floating_point<T>,
detail::is_not_toml_type<T, basic_value<TC>>,
cxx::negation<detail::has_from_toml_method<T, TC>>,
cxx::negation<detail::has_specialized_from<T>>
>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.is_floating())
{
return ok(static_cast<T>(v.as_floating(std::nothrow)));
}
else
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::floating));
}
}
// ============================================================================
// std::string_view
#if defined(TOML11_HAS_STRING_VIEW)
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, std::string_view>::value,
result<std::string_view, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.is_string())
{
return ok(std::string_view(v.as_string(std::nothrow)));
}
else
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::string));
}
}
#endif // string_view
// ============================================================================
// std::chrono::duration from toml::local_time
template<typename T, typename TC>
cxx::enable_if_t<detail::is_chrono_duration<T>::value,
result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.is_local_time())
{
return ok(std::chrono::duration_cast<T>(
std::chrono::nanoseconds(v.as_local_time(std::nothrow))));
}
else
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::local_time));
}
}
// ============================================================================
// std::chrono::system_clock::time_point from toml::datetime variants
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<std::chrono::system_clock::time_point, T>::value,
result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
switch(v.type())
{
case value_t::local_date:
{
return ok(std::chrono::system_clock::time_point(v.as_local_date(std::nothrow)));
}
case value_t::local_datetime:
{
return ok(std::chrono::system_clock::time_point(v.as_local_datetime(std::nothrow)));
}
case value_t::offset_datetime:
{
return ok(std::chrono::system_clock::time_point(v.as_offset_datetime(std::nothrow)));
}
default:
{
const auto loc = v.location();
return err(make_error_info(error_kind::type_error, "toml::try_get(): bad_cast to "
"std::chrono::system_clock::time_point", loc,
"the actual type is " + to_string(v.type())));
}
}
}
// ============================================================================
// array-like types; most likely STL container, like std::vector, etc.
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>, // T is a container
detail::has_push_back_method<T>, // .push_back() works
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.type() != toml::value_t::array)
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::array));
}
using value_type = typename T::value_type;
const auto& a = v.as_array(std::nothrow);
T container;
detail::try_reserve(container, a.size()); // if T has .reserve(), call it
for(const auto& elem : a)
{
auto converted = try_get<value_type>(elem);
if(converted.is_err())
{
return err(converted.as_err());
}
container.push_back(std::move(converted.as_ok()));
}
return ok(container);
}
// ============================================================================
// std::array
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_array<T>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.type() != toml::value_t::array)
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::array));
}
using value_type = typename T::value_type;
const auto& a = v.as_array(std::nothrow);
T container;
if(a.size() != container.size())
{
const auto loc = v.location();
return err(make_error_info(error_kind::out_of_range, "toml::try_get: while converting to an array: "
" array size is " + std::to_string(container.size()) +
" but there are " + std::to_string(a.size()) + " elements in toml array.",
loc, "here"));
}
for(std::size_t i=0; i<a.size(); ++i)
{
auto converted = try_get<value_type>(a[i]);
if(converted.is_err())
{
return err(converted.as_err());
}
container[i] = std::move(converted.as_ok());
}
return ok(container);
}
// ============================================================================
// std::forward_list
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_forward_list<T>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.type() != toml::value_t::array)
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::array));
}
using value_type = typename T::value_type;
T container;
for(const auto& elem : v.as_array(std::nothrow))
{
auto converted = try_get<value_type>(elem);
if(converted.is_err())
{
return err(converted.as_err());
}
container.push_front(std::move(converted.as_ok()));
}
container.reverse();
return ok(container);
}
// ============================================================================
// std::pair
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_pair<T>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.type() != toml::value_t::array)
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::array));
}
using first_type = typename T::first_type;
using second_type = typename T::second_type;
const auto& ar = v.as_array(std::nothrow);
if(ar.size() != 2)
{
const auto loc = v.location();
return err(make_error_info(error_kind::out_of_range, "toml::try_get: while converting std::pair: "
" but there are " + std::to_string(ar.size()) +
" > 2 elements in toml array.",
loc, "here"));
}
auto first_result = try_get<first_type>(ar[0]);
if(first_result.is_err())
{
return err(first_result.as_err());
}
auto second_result = try_get<second_type>(ar[1]);
if(second_result.is_err())
{
return err(second_result.as_err());
}
return ok(std::make_pair(std::move(first_result.as_ok()),
std::move(second_result.as_ok())));
}
// ============================================================================
// std::tuple.
namespace detail
{
template<typename T, std::size_t I, std::size_t N>
struct try_get_tuple_impl
{
template<typename Array, typename U>
static result<T, error_info> invoke(const Array& a, U curr) noexcept
{
assert(I < a.size());
using value_type = typename std::tuple_element<I, T>::type;
auto converted = try_get<value_type>(a[I]);
if(converted.is_err())
{
return err(converted.as_err());
}
return try_get_tuple_impl<T, I+1, N>::invoke(a, std::tuple_cat(
std::move(curr), std::make_tuple(std::move(converted.as_ok()))));
}
};
template<typename T, std::size_t I>
struct try_get_tuple_impl<T, I, I>
{
template<typename Array>
static result<T, error_info> invoke(const Array&, T x) noexcept
{
return ok(std::move(x));
}
};
} // detail
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_tuple<T>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
if(v.type() != toml::value_t::array)
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::array));
}
const auto& ar = v.as_array(std::nothrow);
if(ar.size() != std::tuple_size<T>::value)
{
const auto loc = v.location();
return err(make_error_info(error_kind::out_of_range,
"toml::try_get: while converting std::tuple: "
" there are " + std::to_string(ar.size()) + " > " +
std::to_string(std::tuple_size<T>::value) + " elements in toml array.",
loc, "here"));
}
return detail::try_get_tuple_impl<T, 0, std::tuple_size<T>::value>::invoke(
ar, std::make_tuple());
}
// ============================================================================
// map-like types; most likely STL map, like std::map or std::unordered_map.
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
using key_type = typename T::key_type;
using mapped_type = typename T::mapped_type;
static_assert(
std::is_convertible<typename basic_value<TC>::key_type, key_type>::value,
"toml::get only supports map type of which key_type is "
"convertible from toml::basic_value::key_type.");
if(v.type() != toml::value_t::table)
{
return err(detail::make_type_error(v, "try_get()", toml::value_t::table));
}
T m;
for(const auto& kv : v.as_table(std::nothrow))
{
auto converted = try_get<mapped_type>(kv.second);
if(converted.is_err())
{
return err(converted.as_err());
}
m.emplace(key_type(kv.first), std::move(converted.as_ok()));
}
return ok(m);
}
// ============================================================================
// user-defined type that defines `try_from<T>`.
template<typename T, typename TC>
cxx::enable_if_t<detail::has_specialized_try_from<T>::value, result<T, error_info>>
try_get(const basic_value<TC>& v) noexcept
{
return ::toml::try_from<T>::try_from_toml(v);
}
} // toml
#endif // TOML11_TRY_GET_HPP

View File

@@ -44,7 +44,7 @@ read_dec_int(const std::string& str, const source_location src)
iss >> val;
if(iss.fail())
{
return err(make_error_info("toml::parse_dec_integer: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_dec_integer: "
"too large integer: current max digits = 2^" + std::to_string(max_digits),
std::move(src), "must be < 2^" + std::to_string(max_digits)));
}
@@ -63,7 +63,7 @@ read_hex_int(const std::string& str, const source_location src)
iss >> std::hex >> val;
if(iss.fail())
{
return err(make_error_info("toml::parse_hex_integer: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_hex_integer: "
"too large integer: current max value = 2^" + std::to_string(max_digits),
std::move(src), "must be < 2^" + std::to_string(max_digits)));
}
@@ -82,7 +82,7 @@ read_oct_int(const std::string& str, const source_location src)
iss >> std::oct >> val;
if(iss.fail())
{
return err(make_error_info("toml::parse_oct_integer: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_oct_integer: "
"too large integer: current max value = 2^" + std::to_string(max_digits),
std::move(src), "must be < 2^" + std::to_string(max_digits)));
}
@@ -131,7 +131,7 @@ read_bin_int(const std::string& str, const source_location src)
}
if(base == 0)
{
return err(make_error_info("toml::parse_bin_integer: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_bin_integer: "
"too large integer: current max value = 2^" + std::to_string(max_digits),
std::move(src), "must be < 2^" + std::to_string(max_digits)));
}
@@ -166,7 +166,7 @@ read_hex_float(const std::string& str, const source_location src, float val)
#endif
if(res != 1)
{
return err(make_error_info("toml::parse_floating: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
"failed to read hexadecimal floating point value ",
std::move(src), "here"));
}
@@ -182,7 +182,7 @@ read_hex_float(const std::string& str, const source_location src, double val)
#endif
if(res != 1)
{
return err(make_error_info("toml::parse_floating: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
"failed to read hexadecimal floating point value ",
std::move(src), "here"));
}
@@ -195,7 +195,7 @@ cxx::enable_if_t<cxx::conjunction<
>::value, result<T, error_info>>
read_hex_float(const std::string&, const source_location src, T)
{
return err(make_error_info("toml::parse_floating: failed to read "
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: failed to read "
"floating point value because of unknown type in type_config",
std::move(src), "here"));
}
@@ -209,7 +209,7 @@ read_dec_float(const std::string& str, const source_location src)
iss >> val;
if(iss.fail())
{
return err(make_error_info("toml::parse_floating: "
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
"failed to read floating point value from stream",
std::move(src), "here"));
}

View File

@@ -99,6 +99,47 @@ inline std::string make_string(std::size_t len, char c)
return std::string(len, c);
}
// ---------------------------------------------------------------------------
// It suppresses warnings by -Wsign-conversion when we pass integer literal
// to toml::find. integer literal `0` is deduced as an int, and will be
// converted to std::size_t. This causes sign-conversion.
template<typename TC>
std::size_t key_cast(const std::size_t& v) noexcept
{
return v;
}
template<typename TC, typename T>
cxx::enable_if_t<std::is_integral<cxx::remove_cvref_t<T>>::value, std::size_t>
key_cast(const T& v) noexcept
{
return static_cast<std::size_t>(v);
}
// for string-like (string, string literal, string_view)
template<typename TC>
typename basic_value<TC>::key_type const&
key_cast(const typename basic_value<TC>::key_type& v) noexcept
{
return v;
}
template<typename TC>
typename basic_value<TC>::key_type
key_cast(const typename basic_value<TC>::key_type::value_type* v)
{
return typename basic_value<TC>::key_type(v);
}
#if defined(TOML11_HAS_STRING_VIEW)
template<typename TC>
typename basic_value<TC>::key_type
key_cast(const std::string_view v)
{
return typename basic_value<TC>::key_type(v);
}
#endif // string_view
} // namespace detail
} // namespace toml
#endif // TOML11_UTILITY_HPP

View File

@@ -50,6 +50,9 @@ error_info make_type_error(const basic_value<TC>&, const std::string&, const val
template<typename TC>
error_info make_not_found_error(const basic_value<TC>&, const std::string&, const std::string&);
template<typename TC>
error_info make_not_found_error(const basic_value<TC>&, const std::string&, const std::size_t);
template<typename TC>
void change_region_of_value(basic_value<TC>&, const basic_value<TC>&);
@@ -1613,6 +1616,44 @@ class basic_value
assert(found->first == k);
return found->second;
}
result<std::reference_wrapper<value_type>, error_info>
try_at(const key_type& k) noexcept
{
if(!this->is_table())
{
return err(detail::make_type_error(*this,
"toml::value::try_at(key_type)", value_t::table));
}
auto& table = this->as_table(std::nothrow);
const auto found = table.find(k);
if(found == table.end())
{
return err(detail::make_not_found_error(*this,
"toml::value::try_at(key_type)", k));
}
assert(found->first == k);
return ok(std::ref(found->second));
}
result<std::reference_wrapper<const value_type>, error_info>
try_at(const key_type& k) const noexcept
{
if(!this->is_table())
{
return err(detail::make_type_error(*this,
"toml::value::try_at(key_type)", value_t::table));
}
const auto& table = this->as_table(std::nothrow);
const auto found = table.find(k);
if(found == table.end())
{
return err(detail::make_not_found_error(*this,
"toml::value::try_at(key_type)", k));
}
assert(found->first == k);
return ok(std::cref(found->second));
}
value_type& operator[](const key_type& k)
{
if(this->is_empty())
@@ -1688,6 +1729,41 @@ class basic_value
return ar.at(idx);
}
result<std::reference_wrapper<value_type>, error_info>
try_at(const std::size_t& idx) noexcept
{
if(!this->is_array())
{
return err(detail::make_type_error(*this,
"toml::value::try_at(key_type)", value_t::array));
}
auto& ar = this->as_array(std::nothrow);
if(ar.size() <= idx)
{
return err(detail::make_not_found_error(*this,
"toml::value::try_at(idx)", idx));
}
return ok(std::ref(ar[idx]));
}
result<std::reference_wrapper<const value_type>, error_info>
try_at(const std::size_t idx) const noexcept
{
if(!this->is_array())
{
return err(detail::make_type_error(*this,
"toml::value::try_at(key_type)", value_t::array));
}
const auto& ar = this->as_array(std::nothrow);
if(ar.size() <= idx)
{
return err(detail::make_not_found_error(*this,
"toml::value::try_at(idx)", idx));
}
return ok(std::cref(ar[idx]));
}
value_type& operator[](const std::size_t idx) noexcept
{
// no check...
@@ -1775,20 +1851,19 @@ class basic_value
{
switch(this->type_)
{
case value_t::boolean : { boolean_ .~boolean_storage (); break; }
case value_t::integer : { integer_ .~integer_storage (); break; }
case value_t::floating : { floating_ .~floating_storage (); break; }
case value_t::string : { string_ .~string_storage (); break; }
case value_t::offset_datetime : { offset_datetime_.~offset_datetime_storage (); break; }
case value_t::local_datetime : { local_datetime_ .~local_datetime_storage (); break; }
case value_t::local_date : { local_date_ .~local_date_storage (); break; }
case value_t::local_time : { local_time_ .~local_time_storage (); break; }
case value_t::array : { array_ .~array_storage (); break; }
case value_t::table : { table_ .~table_storage (); break; }
default : { break; }
case value_t::boolean : { boolean_ .~boolean_storage (); return; }
case value_t::integer : { integer_ .~integer_storage (); return; }
case value_t::floating : { floating_ .~floating_storage (); return; }
case value_t::string : { string_ .~string_storage (); return; }
case value_t::offset_datetime : { offset_datetime_.~offset_datetime_storage (); return; }
case value_t::local_datetime : { local_datetime_ .~local_datetime_storage (); return; }
case value_t::local_date : { local_date_ .~local_date_storage (); return; }
case value_t::local_time : { local_time_ .~local_time_storage (); return; }
case value_t::array : { array_ .~array_storage (); return; }
case value_t::table : { table_ .~table_storage (); return; }
default : { return; }
}
this->type_ = value_t::empty;
return;
}
template<typename T, typename U>
@@ -2045,6 +2120,13 @@ error_info make_error_info(
v.location(), std::move(msg), std::forward<Ts>(tail)...);
}
template<typename TC, typename ... Ts>
error_info make_error_info(error_kind k,
std::string title, const basic_value<TC>& v, std::string msg, Ts&& ... tail)
{
return make_error_info(k, std::move(title),
v.location(), std::move(msg), std::forward<Ts>(tail)...);
}
template<typename TC, typename ... Ts>
std::string format_error(std::string title,
const basic_value<TC>& v, std::string msg, Ts&& ... tail)
{
@@ -2058,7 +2140,8 @@ namespace detail
template<typename TC>
error_info make_type_error(const basic_value<TC>& v, const std::string& fname, const value_t ty)
{
return make_error_info(fname + ": bad_cast to " + to_string(ty),
return make_error_info(error_kind::type_error,
fname + ": bad_cast to " + to_string(ty),
v.location(), "the actual type is " + to_string(v.type()));
}
template<typename TC>
@@ -2070,7 +2153,7 @@ error_info make_not_found_error(const basic_value<TC>& v, const std::string& fna
std::vector<std::pair<source_location, std::string>> locs;
if( ! loc.is_ok())
{
return error_info(title, locs);
return error_info(error_kind::out_of_range, title, locs);
}
if(loc.first_line_number() == 1 && loc.first_column_number() == 1 && loc.length() == 1)
@@ -2095,7 +2178,21 @@ error_info make_not_found_error(const basic_value<TC>& v, const std::string& fna
{
locs.emplace_back(v.location(), "in this table");
}
return error_info(title, locs);
return error_info(error_kind::out_of_range, title, locs);
}
template<typename TC>
error_info make_not_found_error(const basic_value<TC>& v, const std::string& fname, const std::size_t idx)
{
if( ! v.is_array())
{
return make_type_error(v, fname, toml::value_t::array);
}
std::ostringstream oss;
oss << "actual length (" << v.as_array(std::nothrow).size()
<< ") is shorter than the specified index (" << idx << ").";
return make_error_info(error_kind::out_of_range,
fname + ": no element corresponding to the index",
v, oss.str());
}
#define TOML11_DETAIL_GENERATE_COMPTIME_GETTER(ty) \

View File

@@ -3,7 +3,7 @@
#define TOML11_VERSION_MAJOR 4
#define TOML11_VERSION_MINOR 0
#define TOML11_VERSION_PATCH 3
#define TOML11_VERSION_PATCH 2
#ifndef __cplusplus
# error "__cplusplus is not defined"
@@ -57,11 +57,6 @@
#define TOML11_CXX20_VALUE 202002L
#endif//TOML11_CXX20_VALUE
#if defined(__cpp_char8_t)
# if __cpp_char8_t >= 201811L
# define TOML11_HAS_CHAR8_T 1
# endif
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE
# if __has_include(<string_view>)

View File

@@ -3,7 +3,7 @@
#define TOML11_VERSION_MAJOR 4
#define TOML11_VERSION_MINOR 0
#define TOML11_VERSION_PATCH 3
#define TOML11_VERSION_PATCH 2
#ifndef __cplusplus
# error "__cplusplus is not defined"
@@ -57,11 +57,6 @@
#define TOML11_CXX20_VALUE 202002L
#endif//TOML11_CXX20_VALUE
#if defined(__cpp_char8_t)
# if __cpp_char8_t >= 201811L
# define TOML11_HAS_CHAR8_T 1
# endif
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE
# if __has_include(<string_view>)
@@ -1948,7 +1943,7 @@ struct source_location
static source_location current() { return source_location{}; }
};
inline std::string to_string(const source_location&)
inline std::string to_string(const source_location& loc)
{
return std::string("");
}
@@ -4078,13 +4073,13 @@ struct result
{
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_);
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.fail_);
auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}
@@ -4093,13 +4088,13 @@ struct result
{
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_));
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.fail_));
auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}
@@ -4110,13 +4105,13 @@ struct result
this->cleanup();
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_);
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.fail_);
auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}
@@ -4128,13 +4123,13 @@ struct result
this->cleanup();
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_));
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.fail_));
auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}
@@ -7350,20 +7345,19 @@ class basic_value
{
switch(this->type_)
{
case value_t::boolean : { boolean_ .~boolean_storage (); break; }
case value_t::integer : { integer_ .~integer_storage (); break; }
case value_t::floating : { floating_ .~floating_storage (); break; }
case value_t::string : { string_ .~string_storage (); break; }
case value_t::offset_datetime : { offset_datetime_.~offset_datetime_storage (); break; }
case value_t::local_datetime : { local_datetime_ .~local_datetime_storage (); break; }
case value_t::local_date : { local_date_ .~local_date_storage (); break; }
case value_t::local_time : { local_time_ .~local_time_storage (); break; }
case value_t::array : { array_ .~array_storage (); break; }
case value_t::table : { table_ .~table_storage (); break; }
default : { break; }
case value_t::boolean : { boolean_ .~boolean_storage (); return; }
case value_t::integer : { integer_ .~integer_storage (); return; }
case value_t::floating : { floating_ .~floating_storage (); return; }
case value_t::string : { string_ .~string_storage (); return; }
case value_t::offset_datetime : { offset_datetime_.~offset_datetime_storage (); return; }
case value_t::local_datetime : { local_datetime_ .~local_datetime_storage (); return; }
case value_t::local_date : { local_date_ .~local_date_storage (); return; }
case value_t::local_time : { local_time_ .~local_time_storage (); return; }
case value_t::array : { array_ .~array_storage (); return; }
case value_t::table : { table_ .~table_storage (); return; }
default : { return; }
}
this->type_ = value_t::empty;
return;
}
template<typename T, typename U>
@@ -10997,7 +10991,6 @@ TOML11_INLINE either string(const spec& s)
TOML11_INLINE non_ascii_key_char::non_ascii_key_char(const spec& s) noexcept
{
assert(s.v1_1_0_allow_non_english_in_bare_keys);
(void)s; // for NDEBUG
}
TOML11_INLINE std::uint32_t non_ascii_key_char::read_utf8(location& loc) const
@@ -15407,6 +15400,12 @@ inline namespace toml_literals
::toml::value operator"" _toml(const char* str, std::size_t len);
#if defined(__cpp_char8_t)
# if __cpp_char8_t >= 201811L
# define TOML11_HAS_CHAR8_T 1
# endif
#endif
#if defined(TOML11_HAS_CHAR8_T)
// value of u8"" literal has been changed from char to char8_t and char8_t is
// NOT compatible to char

View File

@@ -99,7 +99,6 @@ if(TOML11_PRECOMPILE)
# required options to use toml11 with MSVC
if(MSVC)
target_compile_options(toml11 PUBLIC "/utf-8")
target_compile_options(toml11 PRIVATE "/W4" "/WX")
if(MSVC_VERSION LESS 1910)
message(STATUS "MSVC < 1910. DEFINE_CONVERSION_NON_INTRUSIVE is disabled")
target_compile_definitions(toml11 PUBLIC -DTOML11_WITHOUT_DEFINE_NON_INTRUSIVE)
@@ -108,22 +107,6 @@ if(TOML11_PRECOMPILE)
else() # MSVC 2019
target_compile_options(toml11 PUBLIC "/Zc:preprocessor")
endif()
else()
target_compile_options(toml11 PRIVATE
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WERROR}>: -Werror >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
)
endif()
else()
add_library(toml11 INTERFACE)

View File

@@ -3,11 +3,13 @@ set(TOML11_TEST_NAMES
test_datetime
test_error_message
test_find
test_try_find
test_find_or
test_format_integer
test_format_floating
test_format_table
test_get
test_try_get
test_get_or
test_location
test_literal
@@ -41,6 +43,23 @@ set(TOML11_TEST_NAMES
test_visit
)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-Wall" COMPILER_SUPPORTS_WALL)
check_cxx_compiler_flag("-Wextra" COMPILER_SUPPORTS_WEXTRA)
check_cxx_compiler_flag("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
check_cxx_compiler_flag("-Werror" COMPILER_SUPPORTS_WERROR)
check_cxx_compiler_flag("-Wsign-conversion" COMPILER_SUPPORTS_WSIGN_CONVERSION)
check_cxx_compiler_flag("-Wconversion" COMPILER_SUPPORTS_WCONVERSION)
check_cxx_compiler_flag("-Wduplicated-cond" COMPILER_SUPPORTS_WDUPLICATED_COND)
check_cxx_compiler_flag("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
check_cxx_compiler_flag("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
check_cxx_compiler_flag("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
check_cxx_compiler_flag("-Wrange-loop-analysis" COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
check_cxx_compiler_flag("-Wundef" COMPILER_SUPPORTS_WUNDEF)
check_cxx_compiler_flag("-Wshadow" COMPILER_SUPPORTS_WSHADOW)
if(BUILD_TESTING)
add_library(toml11_test_utility STATIC utility.cpp)
target_include_directories(toml11_test_utility
@@ -55,28 +74,27 @@ if(BUILD_TESTING)
)
target_link_libraries(${TEST_NAME} PUBLIC toml11 toml11_test_utility)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
target_compile_options(${TEST_NAME} PRIVATE /W3)
else()
target_compile_options(${TEST_NAME} PRIVATE
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WERROR}>: -Werror >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
target_link_options(${TEST_NAME} PRIVATE
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
@@ -95,27 +113,27 @@ if(TOML11_BUILD_TOML_TESTS)
)
target_link_libraries(toml11_decoder PRIVATE toml11)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
target_compile_options(${TEST_NAME} PRIVATE /W3)
else()
target_compile_options(toml11_decoder PRIVATE
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
target_link_options(toml11_decoder PRIVATE
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
endif()
@@ -127,7 +145,7 @@ if(TOML11_BUILD_TOML_TESTS)
target_compile_definitions(toml11_decoder_v1_1_0 PRIVATE -DTOML11_TO_JSON_USE_V1_1_0)
target_link_libraries(toml11_decoder_v1_1_0 PRIVATE toml11)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
target_compile_options(${TEST_NAME} PRIVATE /W3)
else()
target_compile_options(toml11_decoder_v1_1_0 PRIVATE
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
@@ -158,27 +176,27 @@ if(TOML11_BUILD_TOML_TESTS)
)
target_link_libraries(toml11_encoder PRIVATE toml11)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
target_compile_options(${TEST_NAME} PRIVATE /W3)
else()
target_compile_options(toml11_encoder PRIVATE
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
target_link_options(toml11_encoder PRIVATE
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
endif()
endif(TOML11_BUILD_TOML_TESTS)

829
tests/test_try_find.cpp Normal file
View File

@@ -0,0 +1,829 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include "utility.hpp"
#include <toml11/value.hpp>
#include <toml11/try_find.hpp>
#include <array>
#include <deque>
#include <list>
#include <map>
#include <tuple>
#include <unordered_map>
#if defined(TOML11_HAS_STRING_VIEW)
#include <string_view>
#endif
namespace toml
{
namespace detail
{
std::tm localtime_s(const std::time_t* src);
std::tm gmtime_s(const std::time_t* src);
} // detail
} // toml
TEST_CASE("testing toml::try_find with toml type")
{
using value_type = toml::value;
using boolean_type = typename value_type::boolean_type ;
using integer_type = typename value_type::integer_type ;
using floating_type = typename value_type::floating_type ;
using string_type = typename value_type::string_type ;
using local_time_type = typename value_type::local_time_type ;
using local_date_type = typename value_type::local_date_type ;
using local_datetime_type = typename value_type::local_datetime_type ;
using offset_datetime_type = typename value_type::offset_datetime_type;
using array_type = typename value_type::array_type ;
using table_type = typename value_type::table_type ;
{
value_type v(toml::table{{"a", true}});
CHECK_EQ(true, toml::try_find<boolean_type>(v, "a").unwrap());
toml::try_find<boolean_type>(v, "a").unwrap() = false;
CHECK_EQ(false, toml::try_find<boolean_type>(v, "a").unwrap());
boolean_type x = toml::try_find<boolean_type>(std::move(v), "a").unwrap();
CHECK_EQ(false, x);
}
{
value_type v(toml::table{{"a", 42}});
CHECK_EQ(integer_type(42), toml::try_find<integer_type>(v, "a").unwrap());
toml::try_find<integer_type>(v, "a").unwrap() = 54;
CHECK_EQ(integer_type(54), toml::try_find<integer_type>(v, "a").unwrap());
integer_type x = toml::try_find<integer_type>(std::move(v), "a").unwrap();
CHECK_EQ(integer_type(54), x);
}
{
value_type v(toml::table{{"a", 3.14}});
CHECK_EQ(floating_type(3.14), toml::try_find<floating_type>(v, "a").unwrap());
toml::try_find<floating_type>(v, "a").unwrap() = 2.71;
CHECK_EQ(floating_type(2.71), toml::try_find<floating_type>(v, "a").unwrap());
floating_type x = toml::try_find<floating_type>(std::move(v), "a").unwrap();
CHECK_EQ(floating_type(2.71), x);
}
{
value_type v(toml::table{{"a", "foo"}});
CHECK_EQ("foo", toml::try_find<string_type>(v, "a").unwrap());
toml::try_find<string_type>(v, "a").unwrap() += "bar";
CHECK_EQ("foobar", toml::try_find<string_type>(v, "a").unwrap());
string_type x = toml::try_find<string_type>(std::move(v), "a").unwrap();
CHECK_EQ("foobar", x);
}
{
local_date_type d(2018, toml::month_t::Apr, 22);
value_type v(toml::table{{"a", d}});
CHECK_EQ(d, toml::try_find<local_date_type>(v, "a").unwrap());
toml::try_find<local_date_type>(v, "a").unwrap().year = 2017;
d.year = 2017;
CHECK_EQ(d, toml::try_find<local_date_type>(v, "a").unwrap());
local_date_type x = toml::try_find<local_date_type>(std::move(v), "a").unwrap();
CHECK_EQ(d, x);
}
{
local_time_type t(12, 30, 45);
value_type v(toml::table{{"a", t}});
CHECK_EQ(t, toml::try_find<local_time_type>(v, "a").unwrap());
toml::try_find<local_time_type>(v, "a").unwrap().hour = 9;
t.hour = 9;
CHECK_EQ(t, toml::try_find<local_time_type>(v, "a").unwrap());
local_time_type x = toml::try_find<local_time_type>(std::move(v), "a").unwrap();
CHECK_EQ(t, x);
}
{
local_datetime_type dt(toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45));
value_type v(toml::table{{"a", dt}});
CHECK_EQ(dt, toml::try_find<local_datetime_type>(v, "a").unwrap());
toml::try_find<local_datetime_type>(v, "a").unwrap().date.year = 2017;
dt.date.year = 2017;
CHECK_EQ(dt, toml::try_find<local_datetime_type>(v, "a").unwrap());
toml::local_datetime x = toml::try_find<local_datetime_type>(std::move(v), "a").unwrap();
CHECK_EQ(dt, x);
}
{
offset_datetime_type dt(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45)), toml::time_offset(9, 0));
value_type v(toml::table{{"a", dt}});
CHECK_EQ(dt, toml::try_find<offset_datetime_type>(v, "a").unwrap());
toml::try_find<toml::offset_datetime>(v, "a").unwrap().date.year = 2017;
dt.date.year = 2017;
CHECK_EQ(dt, toml::try_find<offset_datetime_type>(v, "a").unwrap());
offset_datetime_type x = toml::try_find<offset_datetime_type>(std::move(v), "a").unwrap();
CHECK_EQ(dt, x);
}
{
array_type vec;
vec.push_back(value_type(42));
vec.push_back(value_type(54));
value_type v(toml::table{{"a", vec}});
CHECK_EQ(vec, toml::try_find<array_type>(v, "a").unwrap());
toml::try_find<array_type>(v, "a").unwrap().push_back(value_type(123));
vec.push_back(value_type(123));
CHECK_EQ(vec, toml::try_find<array_type>(v, "a").unwrap());
array_type x = toml::try_find<array_type>(std::move(v), "a").unwrap();
CHECK_EQ(vec, x);
}
{
table_type tab;
tab["key1"] = value_type(42);
tab["key2"] = value_type(3.14);
value_type v(toml::table{{"a", tab}});
CHECK_EQ(tab, toml::try_find<table_type>(v, "a").unwrap());
toml::try_find<table_type>(v, "a").unwrap()["key3"] = value_type(123);
tab["key3"] = value_type(123);
CHECK_EQ(tab, toml::try_find<table_type>(v, "a").unwrap());
table_type x = toml::try_find<table_type>(std::move(v), "a").unwrap();
CHECK_EQ(tab, x);
}
{
value_type v1(toml::table{{"a", 42}});
CHECK_EQ(toml::value(42), toml::try_find(v1, "a").unwrap());
value_type v2(54);
toml::try_find(v1, "a").unwrap() = v2;
CHECK_EQ(v2, toml::try_find(v1, "a").unwrap());
value_type x = toml::try_find(std::move(v1), "a").unwrap();
CHECK_EQ(v2, x);
}
}
TEST_CASE("testing try_find fails")
{
using value_type = toml::value;
using boolean_type = typename value_type::boolean_type ;
using integer_type = typename value_type::integer_type ;
// -----------------------------------------------------------------------
// const-reference version
{
// value is not a table
const toml::value v(true);
CHECK_UNARY(toml::try_find<boolean_type>(v, "key").is_err());
}
{
// the value corresponding to the key is not the expected type
const toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<boolean_type>(v, "key").is_err());
}
{
// the value corresponding to the key is not found
const toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<integer_type>(v, "different_key").is_err());
}
{
// the positive control.
const toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<int>(v, "key").is_ok());
}
// -----------------------------------------------------------------------
// reference version
{
// value is not a table
toml::value v(true);
CHECK_UNARY(toml::try_find<boolean_type>(v, "key").is_err());
}
{
// the value corresponding to the key is not the expected type
toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<boolean_type>(v, "key").is_err());
}
{
// the value corresponding to the key is not found
toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<integer_type>(v, "different_key").is_err());
}
{
// the positive control.
toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<int>(v, "key").is_ok());
}
// -----------------------------------------------------------------------
// move version
{
// value is not a table
toml::value v(true);
CHECK_UNARY(toml::try_find<boolean_type>(std::move(v), "key").is_err());
}
{
// the value corresponding to the key is not the expected type
toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<boolean_type>(std::move(v), "key").is_err());
}
{
// the value corresponding to the key is not found
toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<integer_type>(std::move(v), "different_key").is_err());
}
{
// the positive control.
toml::value v = toml::table{{"key", 42}};
CHECK_UNARY(toml::try_find<int>(std::move(v), "key").is_ok());
}
}
TEST_CASE("testing toml::try_find(v, idx) throws")
{
using value_type = toml::value;
using boolean_type = typename value_type::boolean_type ;
using integer_type = typename value_type::integer_type ;
// -----------------------------------------------------------------------
// const-reference version
{
// value is not an array
const toml::value v(true);
CHECK_UNARY(toml::try_find<boolean_type>(v, 0).is_err());
}
{
// the value corresponding to the key is not the expected type
const toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<boolean_type>(v, 0).is_err());
}
{
// the value corresponding to the key is not found
const toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<integer_type>(v, 6).is_err());
}
{
// the positive control.
const toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<int>(v, 2).is_ok());
}
// -----------------------------------------------------------------------
// non-const reference version
{
// value is not an array
toml::value v(true);
CHECK_UNARY(toml::try_find<boolean_type>(v, 0).is_err());
}
{
// the value corresponding to the key is not the expected type
toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<boolean_type>(v, 0).is_err());
}
{
// the value corresponding to the key is not found
toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<integer_type>(v, 6).is_err());
}
{
// the positive control.
toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<int>(v, 2).is_ok());
}
// -----------------------------------------------------------------------
// move version
{
// value is not an array
toml::value v(true);
CHECK_UNARY(toml::try_find<boolean_type>(std::move(v), 0).is_err());
}
{
// the value corresponding to the key is not the expected type
toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<boolean_type>(std::move(v), 0).is_err());
}
{
// the value corresponding to the key is not found
toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<integer_type>(std::move(v), 6).is_err());
}
{
// the positive control.
toml::value v = toml::array{1, 2, 3, 4, 5};
CHECK_UNARY(toml::try_find<int>(std::move(v), 2).is_ok());
}
}
TEST_CASE("testing toml::try_find with recursive table/array")
{
using value_type = toml::value;
using integer_type = typename value_type::integer_type ;
// recursively search tables
{
toml::value v = toml::table{
{"a", toml::table{
{"b", toml::table{
{"c", toml::table{
{"d", 42}
}}
}}
}}
};
CHECK_EQ(42, toml::try_find<int>(v, "a", "b", "c", "d").unwrap());
// reference that can be used to modify the content
auto num = toml::try_find<integer_type>(v, "a", "b", "c", "d");
CHECK_UNARY(num.is_ok());
num.unwrap() = 54;
CHECK_EQ(54, toml::try_find<int>(v, "a", "b", "c", "d").unwrap());
const std::string a("a"), b("b"), c("c"), d("d");
auto num2 = toml::try_find<integer_type>(v, a, b, c, d);
CHECK_UNARY(num2.is_ok());
num2.unwrap() = 42;
CHECK_EQ(42, toml::try_find<int>(v, a, b, c, d).unwrap());
auto num3 = toml::try_find<integer_type>(v, a, "b", c, "d");
CHECK_EQ(42, num3.unwrap());
auto num4 = toml::try_find<integer_type>(std::move(v), a, b, c, d);
CHECK_EQ(42, num4.unwrap());
}
// recursively search arrays
{
toml::value v = toml::array{
toml::array{"array", "of", "string"},
toml::array{toml::array{1, 2, 3}, toml::array{3.14, 2.71}}
};
CHECK_EQ("array" , toml::try_find<std::string>(v, 0, 0).unwrap());
CHECK_EQ("of" , toml::try_find<std::string>(v, 0, 1).unwrap());
CHECK_EQ("string", toml::try_find<std::string>(v, 0, 2).unwrap());
CHECK_EQ(1, toml::try_find<int>(v, 1, 0, 0).unwrap());
CHECK_EQ(2, toml::try_find<int>(v, 1, 0, 1).unwrap());
CHECK_EQ(3, toml::try_find<int>(v, 1, 0, 2).unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, 1, 1, 0).unwrap());
CHECK_EQ(2.71, toml::try_find<double>(v, 1, 1, 1).unwrap());
// reference that can be used to modify the content
auto num = toml::try_find<integer_type>(v, 1, 0, 2);
num.unwrap() = 42;
CHECK_EQ( 1, toml::try_find<int>(v, 1, 0, 0).unwrap());
CHECK_EQ( 2, toml::try_find<int>(v, 1, 0, 1).unwrap());
CHECK_EQ(42, toml::try_find<int>(v, 1, 0, 2).unwrap());
// move value
auto num2 = toml::try_find<integer_type>(std::move(v), 1, 0, 2);
CHECK_EQ(42, num2.unwrap());
}
// recursively search mixtures
{
toml::value v = toml::table{{"array", toml::array{
toml::array{1, 2, 3},
toml::array{
toml::table{{"foo", "bar"}, {"baz", "qux"}},
toml::table{{"pi", 3.14}, {"e", 2.71}}
}}
}};
CHECK_EQ(1, toml::try_find<int>(v, "array", 0, 0).unwrap());
CHECK_EQ(2, toml::try_find<int>(v, "array", 0, 1).unwrap());
CHECK_EQ(3, toml::try_find<int>(v, "array", 0, 2).unwrap());
CHECK_EQ("bar", toml::try_find<std::string>(v, "array", 1, 0, "foo").unwrap());
CHECK_EQ("qux", toml::try_find<std::string>(v, "array", 1, 0, "baz").unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, "array", 1, 1, "pi").unwrap());
CHECK_EQ(2.71, toml::try_find<double>(v, "array", 1, 1, "e" ).unwrap());
const std::string ar("array");
const auto ar_c = "array";
const std::string pi("pi");
const auto pi_c = "pi";
CHECK_EQ(3.14, toml::try_find<double>(v, ar, 1, 1, "pi").unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, ar, 1, 1, pi) .unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, ar, 1, 1, pi_c).unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, ar_c, 1, 1, "pi").unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, ar_c, 1, 1, pi) .unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, ar_c, 1, 1, pi_c).unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, "array", 1, 1, pi) .unwrap());
CHECK_EQ(3.14, toml::try_find<double>(v, "array", 1, 1, pi_c).unwrap());
}
}
TEST_CASE("testing toml::try_find integer conversion")
{
using value_type = toml::value;
{
value_type v = toml::table{{"key", 42}};
CHECK_EQ(int(42) , toml::try_find<int >(v, "key").unwrap());
CHECK_EQ(short(42) , toml::try_find<short >(v, "key").unwrap());
CHECK_EQ(char(42) , toml::try_find<char >(v, "key").unwrap());
CHECK_EQ(unsigned(42) , toml::try_find<unsigned >(v, "key").unwrap());
CHECK_EQ(long(42) , toml::try_find<long >(v, "key").unwrap());
CHECK_EQ(std::int64_t(42) , toml::try_find<std::int64_t >(v, "key").unwrap());
CHECK_EQ(std::uint64_t(42), toml::try_find<std::uint64_t>(v, "key").unwrap());
CHECK_EQ(std::int16_t(42) , toml::try_find<std::int16_t >(v, "key").unwrap());
CHECK_EQ(std::uint16_t(42), toml::try_find<std::uint16_t>(v, "key").unwrap());
CHECK_EQ(std::uint16_t(42), toml::try_find<std::uint16_t>(std::move(v), "key").unwrap());
}
}
TEST_CASE("testing toml::try_find floating conversion")
{
using value_type = toml::value;
{
value_type v = toml::table{{"key", 3.14}};
const double ref(3.14);
CHECK_EQ(static_cast<float >(ref), toml::try_find<float >(v, "key").unwrap());
CHECK_EQ( ref , toml::try_find<double >(v, "key").unwrap());
CHECK_EQ(static_cast<long double>(ref), toml::try_find<long double>(v, "key").unwrap());
CHECK_EQ(static_cast<float >(ref), toml::try_find<float >(std::move(v), "key").unwrap());
}
}
TEST_CASE("testing toml::try_find string conversion")
{
using value_type = toml::value;
{
value_type v = toml::table{{"key", "foo"}};
CHECK_EQ("foo", toml::try_find<std::string>(v, "key").unwrap());
toml::try_find<std::string>(v, "key").unwrap() += "bar";
CHECK_EQ("foobar", toml::try_find<std::string>(v, "key").unwrap());
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
{
value_type v = toml::table{{"key", "foo"}};
CHECK_EQ("foo", toml::try_find<std::string_view>(v, "key").unwrap());
}
#endif
}
TEST_CASE("testing toml::try_find array conversion")
{
using value_type = toml::value;
value_type v = toml::table{{"key", toml::array{42, 54, 69, 72}}};
const std::vector<int> vec = toml::try_find<std::vector<int>>(v, "key").unwrap();
const std::list<short> lst = toml::try_find<std::list<short>>(v, "key").unwrap();
const std::deque<std::int64_t> deq = toml::try_find<std::deque<std::int64_t>>(v, "key").unwrap();
CHECK_EQ(42, vec.at(0));
CHECK_EQ(54, vec.at(1));
CHECK_EQ(69, vec.at(2));
CHECK_EQ(72, vec.at(3));
std::list<short>::const_iterator iter = lst.begin();
CHECK_EQ(static_cast<short>(42), *(iter++));
CHECK_EQ(static_cast<short>(54), *(iter++));
CHECK_EQ(static_cast<short>(69), *(iter++));
CHECK_EQ(static_cast<short>(72), *(iter++));
CHECK_EQ(static_cast<std::int64_t>(42), deq.at(0));
CHECK_EQ(static_cast<std::int64_t>(54), deq.at(1));
CHECK_EQ(static_cast<std::int64_t>(69), deq.at(2));
CHECK_EQ(static_cast<std::int64_t>(72), deq.at(3));
std::array<int, 4> ary = toml::try_find<std::array<int, 4>>(v, "key").unwrap();
CHECK_EQ(42, ary.at(0));
CHECK_EQ(54, ary.at(1));
CHECK_EQ(69, ary.at(2));
CHECK_EQ(72, ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::try_find<std::tuple<int, short, unsigned, long>>(v, "key").unwrap();
CHECK_EQ( 42 , std::get<0>(tpl));
CHECK_EQ(static_cast<short >(54), std::get<1>(tpl));
CHECK_EQ(static_cast<unsigned>(69), std::get<2>(tpl));
CHECK_EQ(static_cast<long >(72), std::get<3>(tpl));
value_type p = toml::table{{"key", toml::array{3.14, 2.71}}};
std::pair<double, double> pr = toml::try_find<std::pair<double, double> >(p, "key").unwrap();
CHECK_EQ(3.14, pr.first);
CHECK_EQ(2.71, pr.second);
}
TEST_CASE("testing toml::try_find array move conversion")
{
using value_type = toml::value;
value_type v1 = toml::table{{"key", toml::array{42, 54, 69, 72}}};
value_type v2 = toml::table{{"key", toml::array{42, 54, 69, 72}}};
value_type v3 = toml::table{{"key", toml::array{42, 54, 69, 72}}};
value_type v4 = toml::table{{"key", toml::array{42, 54, 69, 72}}};
value_type v5 = toml::table{{"key", toml::array{42, 54, 69, 72}}};
const std::vector<int> vec = toml::try_find<std::vector<int>>(std::move(v1), "key").unwrap();
const std::list<short> lst = toml::try_find<std::list<short>>(std::move(v2), "key").unwrap();
const std::deque<std::int64_t> deq = toml::try_find<std::deque<std::int64_t>>(std::move(v3), "key").unwrap();
CHECK_EQ(42, vec.at(0));
CHECK_EQ(54, vec.at(1));
CHECK_EQ(69, vec.at(2));
CHECK_EQ(72, vec.at(3));
std::list<short>::const_iterator iter = lst.begin();
CHECK_EQ(static_cast<short>(42), *(iter++));
CHECK_EQ(static_cast<short>(54), *(iter++));
CHECK_EQ(static_cast<short>(69), *(iter++));
CHECK_EQ(static_cast<short>(72), *(iter++));
CHECK_EQ(static_cast<std::int64_t>(42), deq.at(0));
CHECK_EQ(static_cast<std::int64_t>(54), deq.at(1));
CHECK_EQ(static_cast<std::int64_t>(69), deq.at(2));
CHECK_EQ(static_cast<std::int64_t>(72), deq.at(3));
std::array<int, 4> ary = toml::try_find<std::array<int, 4>>(std::move(v4), "key").unwrap();
CHECK_EQ(42, ary.at(0));
CHECK_EQ(54, ary.at(1));
CHECK_EQ(69, ary.at(2));
CHECK_EQ(72, ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::try_find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key").unwrap();
CHECK_EQ( 42 , std::get<0>(tpl));
CHECK_EQ(static_cast<short >(54), std::get<1>(tpl));
CHECK_EQ(static_cast<unsigned>(69), std::get<2>(tpl));
CHECK_EQ(static_cast<long >(72), std::get<3>(tpl));
value_type p = toml::table{{"key", toml::array{3.14, 2.71}}};
std::pair<double, double> pr = toml::try_find<std::pair<double, double> >(std::move(p), "key").unwrap();
CHECK_EQ(3.14, pr.first);
CHECK_EQ(2.71, pr.second);
}
TEST_CASE("testing toml::try_find array of array conversion")
{
using value_type = toml::value;
value_type v1 = toml::array{42, 54, 69, 72};
value_type v2 = toml::array{"foo", "bar", "baz"};
value_type v = toml::table{{"key", toml::array{v1, v2}}};
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::try_find<std::pair<std::vector<int>, std::vector<std::string>>>(v, "key").unwrap();
CHECK_EQ(p.first.at(0), 42);
CHECK_EQ(p.first.at(1), 54);
CHECK_EQ(p.first.at(2), 69);
CHECK_EQ(p.first.at(3), 72);
CHECK_EQ(p.second.at(0), "foo");
CHECK_EQ(p.second.at(1), "bar");
CHECK_EQ(p.second.at(2), "baz");
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::try_find<std::tuple<std::vector<int>, std::vector<std::string>>>(v, "key").unwrap();
CHECK_EQ(std::get<0>(t).at(0), 42);
CHECK_EQ(std::get<0>(t).at(1), 54);
CHECK_EQ(std::get<0>(t).at(2), 69);
CHECK_EQ(std::get<0>(t).at(3), 72);
CHECK_EQ(std::get<1>(t).at(0), "foo");
CHECK_EQ(std::get<1>(t).at(1), "bar");
CHECK_EQ(std::get<1>(t).at(2), "baz");
}
TEST_CASE("testing toml::try_find array of array move conversion")
{
using value_type = toml::value;
value_type a1 = toml::array{42, 54, 69, 72};
value_type a2 = toml::array{"foo", "bar", "baz"};
value_type v1 = toml::table{{"key", toml::array{a1, a2}}};
value_type v2 = toml::table{{"key", toml::array{a1, a2}}};
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::try_find<std::pair<std::vector<int>, std::vector<std::string>>>(std::move(v1), "key").unwrap();
CHECK_EQ(p.first.at(0), 42);
CHECK_EQ(p.first.at(1), 54);
CHECK_EQ(p.first.at(2), 69);
CHECK_EQ(p.first.at(3), 72);
CHECK_EQ(p.second.at(0), "foo");
CHECK_EQ(p.second.at(1), "bar");
CHECK_EQ(p.second.at(2), "baz");
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::try_find<std::tuple<std::vector<int>, std::vector<std::string>>>(std::move(v2), "key").unwrap();
CHECK_EQ(std::get<0>(t).at(0), 42);
CHECK_EQ(std::get<0>(t).at(1), 54);
CHECK_EQ(std::get<0>(t).at(2), 69);
CHECK_EQ(std::get<0>(t).at(3), 72);
CHECK_EQ(std::get<1>(t).at(0), "foo");
CHECK_EQ(std::get<1>(t).at(1), "bar");
CHECK_EQ(std::get<1>(t).at(2), "baz");
}
TEST_CASE("testing toml::try_find table conversion")
{
using value_type = toml::value;
{
value_type v1 = toml::table{{"key", toml::table{
{"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}
}}};
const auto v = toml::try_find<std::map<std::string, int>>(v1, "key").unwrap();
CHECK_EQ(v.at("key1"), 1);
CHECK_EQ(v.at("key2"), 2);
CHECK_EQ(v.at("key3"), 3);
CHECK_EQ(v.at("key4"), 4);
}
{
value_type v1 = toml::table{{"key", toml::table{
{"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}
}}};
const auto v = toml::try_find<std::map<std::string, int>>(std::move(v1), "key").unwrap();
CHECK_EQ(v.at("key1"), 1);
CHECK_EQ(v.at("key2"), 2);
CHECK_EQ(v.at("key3"), 3);
CHECK_EQ(v.at("key4"), 4);
}
}
TEST_CASE("testing toml::try_find local_date")
{
using value_type = toml::value;
{
value_type v1 = toml::table{{"key", toml::local_date{2018, toml::month_t::Apr, 1}}};
const auto date = std::chrono::system_clock::to_time_t(
toml::try_find<std::chrono::system_clock::time_point>(v1, "key").unwrap());
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
CHECK_EQ(c, date);
}
{
value_type v1 = toml::table{{"key", toml::local_date{2018, toml::month_t::Apr, 1}}};
const auto date = std::chrono::system_clock::to_time_t(
toml::try_find<std::chrono::system_clock::time_point>(std::move(v1), "key").unwrap());
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
CHECK_EQ(c, date);
}
}
TEST_CASE("testing toml::try_find local_time")
{
using value_type = toml::value;
{
value_type v1 = toml::table{{"key", toml::local_time{12, 30, 45}}};
const auto time = toml::try_find<std::chrono::seconds>(v1, "key").unwrap();
CHECK_EQ(time, std::chrono::hours(12) +
std::chrono::minutes(30) + std::chrono::seconds(45));
}
{
value_type v1 = toml::table{{"key", toml::local_time{12, 30, 45}}};
const auto time = toml::try_find<std::chrono::seconds>(std::move(v1), "key").unwrap();
CHECK_EQ(time, std::chrono::hours(12) +
std::chrono::minutes(30) + std::chrono::seconds(45));
}
}
TEST_CASE("testing toml::try_find local_datetime")
{
using value_type = toml::value;
{
value_type v1 = toml::table{{"key", toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45})}};
const auto date = std::chrono::system_clock::to_time_t(
toml::try_find<std::chrono::system_clock::time_point>(v1, "key").unwrap());
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 12;
t.tm_min = 30;
t.tm_sec = 45;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
CHECK_EQ(c, date);
}
{
value_type v1 = toml::table{{"key", toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45})}};
const auto date = std::chrono::system_clock::to_time_t(
toml::try_find<std::chrono::system_clock::time_point>(std::move(v1), "key").unwrap());
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 12;
t.tm_min = 30;
t.tm_sec = 45;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
CHECK_EQ(c, date);
}
}
TEST_CASE("testing toml::try_find offset_datetime")
{
using value_type = toml::value;
{
value_type v1 = toml::table{{"key", toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{9, 0})}};
// 2018-04-01T12:30:00+09:00
//, 2018-04-01T03:30:00Z
const auto date = toml::try_find<std::chrono::system_clock::time_point>(v1, "key").unwrap();
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tm = toml::detail::gmtime_s(std::addressof(timet));
CHECK_EQ(tm.tm_year + 1900, 2018);
CHECK_EQ(tm.tm_mon + 1, 4);
CHECK_EQ(tm.tm_mday, 1);
CHECK_EQ(tm.tm_hour, 3);
CHECK_EQ(tm.tm_min, 30);
CHECK_EQ(tm.tm_sec, 0);
}
{
value_type v1 = toml::table{{"key", toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{-8, 0})}};
// 2018-04-01T12:30:00-08:00
//, 2018-04-01T20:30:00Z
const auto date = toml::try_find<std::chrono::system_clock::time_point>(v1, "key").unwrap();
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tm = toml::detail::gmtime_s(std::addressof(timet));
CHECK_EQ(tm.tm_year + 1900, 2018);
CHECK_EQ(tm.tm_mon + 1, 4);
CHECK_EQ(tm.tm_mday, 1);
CHECK_EQ(tm.tm_hour, 20);
CHECK_EQ(tm.tm_min, 30);
CHECK_EQ(tm.tm_sec, 0);
}
{
value_type v1 = toml::table{{"key", toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{-8, 0})}};
// 2018-04-01T12:30:00-08:00
//, 2018-04-01T20:30:00Z
const auto date = toml::try_find<std::chrono::system_clock::time_point>(std::move(v1), "key").unwrap();
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tm = toml::detail::gmtime_s(std::addressof(timet));
CHECK_EQ(tm.tm_year + 1900, 2018);
CHECK_EQ(tm.tm_mon + 1, 4);
CHECK_EQ(tm.tm_mday, 1);
CHECK_EQ(tm.tm_hour, 20);
CHECK_EQ(tm.tm_min, 30);
CHECK_EQ(tm.tm_sec, 0);
}
}

529
tests/test_try_get.cpp Normal file
View File

@@ -0,0 +1,529 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include "utility.hpp"
#include <toml11/value.hpp>
#include <toml11/try_get.hpp>
#include <array>
#include <deque>
#include <list>
#include <map>
#include <tuple>
#include <unordered_map>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#endif
namespace toml
{
namespace detail
{
std::tm localtime_s(const std::time_t* src);
std::tm gmtime_s(const std::time_t* src);
} // detail
} // toml
TEST_CASE("testing toml::try_get with toml types")
{
using value_type = toml::value;
using boolean_type = typename value_type::boolean_type ;
using integer_type = typename value_type::integer_type ;
using floating_type = typename value_type::floating_type ;
using string_type = typename value_type::string_type ;
using local_time_type = typename value_type::local_time_type ;
using local_date_type = typename value_type::local_date_type ;
using local_datetime_type = typename value_type::local_datetime_type ;
using offset_datetime_type = typename value_type::offset_datetime_type;
using array_type = typename value_type::array_type ;
using table_type = typename value_type::table_type ;
{
value_type v(true);
CHECK_EQ(true, toml::try_get<boolean_type>(v).unwrap());
toml::try_get<boolean_type>(v).unwrap() = false;
CHECK_EQ(false, toml::try_get<boolean_type>(v).unwrap());
boolean_type x = toml::try_get<boolean_type>(std::move(v)).unwrap();
CHECK_EQ(false, x);
}
{
value_type v(42);
CHECK_EQ(integer_type(42), toml::try_get<integer_type>(v).unwrap());
toml::try_get<integer_type>(v).unwrap() = 54;
CHECK_EQ(integer_type(54), toml::try_get<integer_type>(v).unwrap());
integer_type x = toml::try_get<integer_type>(std::move(v)).unwrap();
CHECK_EQ(integer_type(54), x);
}
{
value_type v(3.14);
CHECK_EQ(floating_type(3.14), toml::try_get<floating_type>(v).unwrap());
toml::try_get<floating_type>(v).unwrap() = 2.71;
CHECK_EQ(floating_type(2.71), toml::try_get<floating_type>(v).unwrap());
floating_type x = toml::try_get<floating_type>(std::move(v)).unwrap();
CHECK_EQ(floating_type(2.71), x);
}
{
value_type v("foo");
CHECK_EQ("foo", toml::try_get<string_type>(v).unwrap());
toml::try_get<string_type>(v).unwrap() += "bar";
CHECK_EQ("foobar", toml::try_get<string_type>(v).unwrap());
string_type x = toml::try_get<string_type>(std::move(v)).unwrap();
CHECK_EQ("foobar", x);
}
{
local_date_type d(2018, toml::month_t::Apr, 22);
value_type v(d);
CHECK_EQ(d, toml::try_get<local_date_type>(v).unwrap());
toml::try_get<local_date_type>(v).unwrap().year = 2017;
d.year = 2017;
CHECK_EQ(d, toml::try_get<local_date_type>(v).unwrap());
local_date_type x = toml::try_get<local_date_type>(std::move(v)).unwrap();
CHECK_EQ(d, x);
}
{
local_time_type t(12, 30, 45);
value_type v(t);
CHECK_EQ(t, toml::try_get<local_time_type>(v).unwrap());
toml::try_get<local_time_type>(v).unwrap().hour = 9;
t.hour = 9;
CHECK_EQ(t, toml::try_get<local_time_type>(v).unwrap());
local_time_type x = toml::try_get<local_time_type>(std::move(v)).unwrap();
CHECK_EQ(t, x);
}
{
local_datetime_type dt(toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45));
value_type v(dt);
CHECK_EQ(dt, toml::try_get<local_datetime_type>(v).unwrap());
toml::try_get<local_datetime_type>(v).unwrap().date.year = 2017;
dt.date.year = 2017;
CHECK_EQ(dt, toml::try_get<local_datetime_type>(v).unwrap());
toml::local_datetime x = toml::try_get<local_datetime_type>(std::move(v)).unwrap();
CHECK_EQ(dt, x);
}
{
offset_datetime_type dt(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 30, 45)), toml::time_offset(9, 0));
value_type v(dt);
CHECK_EQ(dt, toml::try_get<offset_datetime_type>(v).unwrap());
toml::try_get<toml::offset_datetime>(v).unwrap().date.year = 2017;
dt.date.year = 2017;
CHECK_EQ(dt, toml::try_get<offset_datetime_type>(v).unwrap());
offset_datetime_type x = toml::try_get<offset_datetime_type>(std::move(v)).unwrap();
CHECK_EQ(dt, x);
}
{
array_type vec;
vec.push_back(value_type(42));
vec.push_back(value_type(54));
value_type v(vec);
CHECK_EQ(vec, toml::try_get<array_type>(v).unwrap());
toml::try_get<array_type>(v).unwrap().push_back(value_type(123));
vec.push_back(value_type(123));
CHECK_EQ(vec, toml::try_get<array_type>(v).unwrap());
array_type x = toml::try_get<array_type>(std::move(v)).unwrap();
CHECK_EQ(vec, x);
}
{
table_type tab;
tab["key1"] = value_type(42);
tab["key2"] = value_type(3.14);
value_type v(tab);
CHECK_EQ(tab, toml::try_get<table_type>(v).unwrap());
toml::try_get<table_type>(v).unwrap()["key3"] = value_type(123);
tab["key3"] = value_type(123);
CHECK_EQ(tab, toml::try_get<table_type>(v).unwrap());
table_type x = toml::try_get<table_type>(std::move(v)).unwrap();
CHECK_EQ(tab, x);
}
{
value_type v1(42);
CHECK_EQ(v1, toml::try_get<value_type>(v1).unwrap());
value_type v2(54);
toml::try_get<value_type>(v1).unwrap() = v2;
CHECK_EQ(v2, toml::try_get<value_type>(v1).unwrap());
value_type x = toml::try_get<value_type>(std::move(v1)).unwrap();
CHECK_EQ(v2, x);
}
}
TEST_CASE("testing toml::try_get<integer-like>")
{
using value_type = toml::value;
{
value_type v(42);
CHECK_EQ(int(42), toml::try_get<int >(v).unwrap());
CHECK_EQ(short(42), toml::try_get<short >(v).unwrap());
CHECK_EQ(char(42), toml::try_get<char >(v).unwrap());
CHECK_EQ(unsigned(42), toml::try_get<unsigned >(v).unwrap());
CHECK_EQ(long(42), toml::try_get<long >(v).unwrap());
CHECK_EQ(std::int64_t(42), toml::try_get<std::int64_t >(v).unwrap());
CHECK_EQ(std::uint64_t(42), toml::try_get<std::uint64_t>(v).unwrap());
CHECK_EQ(std::int16_t(42), toml::try_get<std::int16_t >(v).unwrap());
CHECK_EQ(std::uint16_t(42), toml::try_get<std::uint16_t>(v).unwrap());
CHECK_EQ(int(42), toml::try_get<int >(as_const(v)).unwrap());
CHECK_EQ(short(42), toml::try_get<short >(as_const(v)).unwrap());
CHECK_EQ(char(42), toml::try_get<char >(as_const(v)).unwrap());
CHECK_EQ(unsigned(42), toml::try_get<unsigned >(as_const(v)).unwrap());
CHECK_EQ(long(42), toml::try_get<long >(as_const(v)).unwrap());
CHECK_EQ(std::int64_t(42), toml::try_get<std::int64_t >(as_const(v)).unwrap());
CHECK_EQ(std::uint64_t(42), toml::try_get<std::uint64_t>(as_const(v)).unwrap());
CHECK_EQ(std::int16_t(42), toml::try_get<std::int16_t >(as_const(v)).unwrap());
CHECK_EQ(std::uint16_t(42), toml::try_get<std::uint16_t>(as_const(v)).unwrap());
value_type v1(v);
value_type v2(v);
value_type v3(v);
value_type v4(v);
value_type v5(v);
value_type v6(v);
value_type v7(v);
value_type v8(v);
value_type v9(v);
CHECK_EQ(int(42), toml::try_get<int >(v1).unwrap());
CHECK_EQ(short(42), toml::try_get<short >(v2).unwrap());
CHECK_EQ(char(42), toml::try_get<char >(v3).unwrap());
CHECK_EQ(unsigned(42), toml::try_get<unsigned >(v4).unwrap());
CHECK_EQ(long(42), toml::try_get<long >(v5).unwrap());
CHECK_EQ(std::int64_t(42), toml::try_get<std::int64_t >(v6).unwrap());
CHECK_EQ(std::uint64_t(42), toml::try_get<std::uint64_t>(v7).unwrap());
CHECK_EQ(std::int16_t(42), toml::try_get<std::int16_t >(v8).unwrap());
CHECK_EQ(std::uint16_t(42), toml::try_get<std::uint16_t>(v9).unwrap());
}
}
TEST_CASE("testing toml::try_get<floating-like>")
{
using value_type = toml::value;
{
const double ref(3.14);
value_type v(ref);
CHECK_EQ(static_cast<float >(ref), toml::try_get<float >(v).unwrap());
CHECK_EQ( ref , toml::try_get<double >(v).unwrap());
CHECK_EQ(static_cast<long double>(ref), toml::try_get<long double>(v).unwrap());
value_type v1(ref);
value_type v2(ref);
value_type v3(ref);
CHECK_EQ(static_cast<float >(ref), toml::try_get<float >(std::move(v1)).unwrap());
CHECK_EQ( ref , toml::try_get<double >(std::move(v2)).unwrap());
CHECK_EQ(static_cast<long double>(ref), toml::try_get<long double>(std::move(v3)).unwrap());
}
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
TEST_CASE("testing toml::try_get<string-like>")
{
using value_type = toml::value;
{
value_type v("foo");
CHECK_EQ("foo", toml::try_get<std::string_view>(v).unwrap());
}
}
#endif
TEST_CASE("testing toml::try_get<array-like>")
{
using value_type = toml::value;
{
const value_type v(toml::array{42, 54, 69, 72});
const std::vector<int> vec = toml::try_get<std::vector<int>>(v).unwrap();
const std::list<short> lst = toml::try_get<std::list<short>>(v).unwrap();
const std::deque<std::int64_t> deq = toml::try_get<std::deque<std::int64_t>>(v).unwrap();
CHECK_EQ(42, vec.at(0));
CHECK_EQ(54, vec.at(1));
CHECK_EQ(69, vec.at(2));
CHECK_EQ(72, vec.at(3));
std::list<short>::const_iterator iter = lst.begin();
CHECK_EQ(static_cast<short>(42), *(iter++));
CHECK_EQ(static_cast<short>(54), *(iter++));
CHECK_EQ(static_cast<short>(69), *(iter++));
CHECK_EQ(static_cast<short>(72), *(iter++));
CHECK_EQ(static_cast<std::int64_t>(42), deq.at(0));
CHECK_EQ(static_cast<std::int64_t>(54), deq.at(1));
CHECK_EQ(static_cast<std::int64_t>(69), deq.at(2));
CHECK_EQ(static_cast<std::int64_t>(72), deq.at(3));
std::array<int, 4> ary = toml::try_get<std::array<int, 4>>(v).unwrap();
CHECK_EQ(42, ary.at(0));
CHECK_EQ(54, ary.at(1));
CHECK_EQ(69, ary.at(2));
CHECK_EQ(72, ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::try_get<std::tuple<int, short, unsigned, long>>(v).unwrap();
CHECK_EQ( 42 , std::get<0>(tpl));
CHECK_EQ(static_cast<short >(54), std::get<1>(tpl));
CHECK_EQ(static_cast<unsigned>(69), std::get<2>(tpl));
CHECK_EQ(static_cast<long >(72), std::get<3>(tpl));
const value_type p(toml::array{3.14, 2.71});
std::pair<double, double> pr = toml::try_get<std::pair<double, double> >(p).unwrap();
CHECK_EQ(3.14, pr.first);
CHECK_EQ(2.71, pr.second);
}
{
value_type v(toml::array{42, 54, 69, 72});
const std::vector<int> vec = toml::try_get<std::vector<int>>(std::move(v)).unwrap();
CHECK_EQ(42, vec.at(0));
CHECK_EQ(54, vec.at(1));
CHECK_EQ(69, vec.at(2));
CHECK_EQ(72, vec.at(3));
}
{
value_type v(toml::array{42, 54, 69, 72});
const std::deque<int> deq = toml::try_get<std::deque<int>>(std::move(v)).unwrap();
CHECK_EQ(42, deq.at(0));
CHECK_EQ(54, deq.at(1));
CHECK_EQ(69, deq.at(2));
CHECK_EQ(72, deq.at(3));
}
{
value_type v(toml::array{42, 54, 69, 72});
const std::list<int> lst = toml::try_get<std::list<int>>(std::move(v)).unwrap();
std::list<int>::const_iterator iter = lst.begin();
CHECK_EQ(42, *(iter++));
CHECK_EQ(54, *(iter++));
CHECK_EQ(69, *(iter++));
CHECK_EQ(72, *(iter++));
}
{
value_type v(toml::array{42, 54, 69, 72});
std::array<int, 4> ary = toml::try_get<std::array<int, 4>>(std::move(v)).unwrap();
CHECK_EQ(42, ary.at(0));
CHECK_EQ(54, ary.at(1));
CHECK_EQ(69, ary.at(2));
CHECK_EQ(72, ary.at(3));
}
{
value_type v(toml::array{42, 54, 69, 72});
std::tuple<int, short, unsigned, long> tpl =
toml::try_get<std::tuple<int, short, unsigned, long>>(std::move(v)).unwrap();
CHECK_EQ( 42 , std::get<0>(tpl));
CHECK_EQ(static_cast<short >(54), std::get<1>(tpl));
CHECK_EQ(static_cast<unsigned>(69), std::get<2>(tpl));
CHECK_EQ(static_cast<long >(72), std::get<3>(tpl));
}
}
TEST_CASE("testing toml::try_get<array-of-arrays>")
{
using value_type = toml::value;
{
const value_type v1(toml::array{42, 54, 69, 72});
const value_type v2(toml::array{"foo", "bar", "baz"});
const value_type v (toml::array{v1, v2});
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::try_get<std::pair<std::vector<int>, std::vector<std::string>>>(v).unwrap();
CHECK_EQ(p.first.size(), 4u);
CHECK_EQ(p.first.at(0), 42);
CHECK_EQ(p.first.at(1), 54);
CHECK_EQ(p.first.at(2), 69);
CHECK_EQ(p.first.at(3), 72);
CHECK_EQ(p.second.size(), 3u);
CHECK_EQ(p.second.at(0), "foo");
CHECK_EQ(p.second.at(1), "bar");
CHECK_EQ(p.second.at(2), "baz");
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::try_get<std::tuple<std::vector<int>, std::vector<std::string>>>(v).unwrap();
CHECK_EQ(std::get<0>(t).at(0), 42);
CHECK_EQ(std::get<0>(t).at(1), 54);
CHECK_EQ(std::get<0>(t).at(2), 69);
CHECK_EQ(std::get<0>(t).at(3), 72);
CHECK_EQ(std::get<1>(t).at(0), "foo");
CHECK_EQ(std::get<1>(t).at(1), "bar");
CHECK_EQ(std::get<1>(t).at(2), "baz");
}
{
const value_type v1(toml::array{42, 54, 69, 72});
const value_type v2(toml::array{"foo", "bar", "baz"});
value_type v (toml::array{v1, v2});
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::try_get<std::pair<std::vector<int>, std::vector<std::string>>>(std::move(v)).unwrap();
CHECK_EQ(p.first.size(), 4u);
CHECK_EQ(p.first.at(0), 42);
CHECK_EQ(p.first.at(1), 54);
CHECK_EQ(p.first.at(2), 69);
CHECK_EQ(p.first.at(3), 72);
CHECK_EQ(p.second.size(), 3u);
CHECK_EQ(p.second.at(0), "foo");
CHECK_EQ(p.second.at(1), "bar");
CHECK_EQ(p.second.at(2), "baz");
}
}
TEST_CASE("testing toml::try_get<table-like>")
{
using value_type = toml::value;
{
const value_type v1(toml::table{
{"key1", 1},
{"key2", 2},
{"key3", 3},
{"key4", 4}
});
const auto v = toml::try_get<std::map<std::string, int>>(v1).unwrap();
CHECK_EQ(v.at("key1"), 1);
CHECK_EQ(v.at("key2"), 2);
CHECK_EQ(v.at("key3"), 3);
CHECK_EQ(v.at("key4"), 4);
}
{
value_type v1(toml::table{
{"key1", 1},
{"key2", 2},
{"key3", 3},
{"key4", 4}
});
const auto v = toml::try_get<std::map<std::string, int>>(std::move(v1)).unwrap();
CHECK_EQ(v.at("key1"), 1);
CHECK_EQ(v.at("key2"), 2);
CHECK_EQ(v.at("key3"), 3);
CHECK_EQ(v.at("key4"), 4);
}
}
TEST_CASE("testing toml::try_get<time_point>(local_date)")
{
using value_type = toml::value;
value_type v1(toml::local_date{2018, toml::month_t::Apr, 1});
const auto date = std::chrono::system_clock::to_time_t(
toml::try_get<std::chrono::system_clock::time_point>(v1).unwrap());
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
CHECK_EQ(c, date);
}
TEST_CASE("testing toml::try_get<duration>")
{
using value_type = toml::value;
value_type v1(toml::local_time{12, 30, 45});
const auto time = toml::try_get<std::chrono::seconds>(v1).unwrap();
const bool result = time == std::chrono::hours(12) +
std::chrono::minutes(30) +
std::chrono::seconds(45);
CHECK_UNARY(result);
}
TEST_CASE("testing toml::try_get<time_point>(local_datetime)")
{
using value_type = toml::value;
value_type v1(toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45}));
const auto date = std::chrono::system_clock::to_time_t(
toml::try_get<std::chrono::system_clock::time_point>(v1).unwrap());
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 12;
t.tm_min = 30;
t.tm_sec = 45;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
CHECK_EQ(c, date);
}
TEST_CASE("testing toml::try_get<time_point>(offset_datetime)")
{
using value_type = toml::value;
{
value_type v1(toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{9, 0}));
// 2018-04-01T12:30:00+09:00
// == 2018-04-01T03:30:00Z
const auto date = toml::try_get<std::chrono::system_clock::time_point>(v1).unwrap();
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tm = toml::detail::gmtime_s(std::addressof(timet));
CHECK_EQ(tm.tm_year + 1900, 2018);
CHECK_EQ(tm.tm_mon + 1, 4);
CHECK_EQ(tm.tm_mday, 1);
CHECK_EQ(tm.tm_hour, 3);
CHECK_EQ(tm.tm_min, 30);
CHECK_EQ(tm.tm_sec, 0);
}
{
value_type v1(toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{-8, 0}));
// 2018-04-01T12:30:00-08:00
//, 2018-04-01T20:30:00Z
const auto date = toml::try_get<std::chrono::system_clock::time_point>(v1).unwrap();
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tm = toml::detail::gmtime_s(std::addressof(timet));
CHECK_EQ(tm.tm_year + 1900, 2018);
CHECK_EQ(tm.tm_mon + 1, 4);
CHECK_EQ(tm.tm_mday, 1);
CHECK_EQ(tm.tm_hour, 20);
CHECK_EQ(tm.tm_min, 30);
CHECK_EQ(tm.tm_sec, 0);
}
}

View File

@@ -1062,21 +1062,89 @@ TEST_CASE("testing array-accessors")
{
toml::value x({true, 42, "hoge"});
// at
CHECK_UNARY(x.at(0).is_boolean());
CHECK_UNARY(x.at(1).is_integer());
CHECK_UNARY(x.at(2).is_string());
CHECK_EQ(x.at(0).as_boolean(), true);
CHECK_EQ(x.at(1).as_integer(), 42);
CHECK_EQ(x.at(2).as_string(), std::string("hoge"));
CHECK_THROWS_AS(x.at(3), std::out_of_range);
CHECK_UNARY(as_const(x).at(0).is_boolean());
CHECK_UNARY(as_const(x).at(1).is_integer());
CHECK_UNARY(as_const(x).at(2).is_string());
CHECK_EQ(x.at(0).as_boolean(), true);
CHECK_EQ(x.at(1).as_integer(), 42);
CHECK_EQ(x.at(2).as_string(), std::string("hoge"));
CHECK_EQ(as_const(x).at(0).as_boolean(), true);
CHECK_EQ(as_const(x).at(1).as_integer(), 42);
CHECK_EQ(as_const(x).at(2).as_string(), std::string("hoge"));
CHECK_THROWS_AS(as_const(x).at(3), std::out_of_range);
// update through at
x.at(0) = false;
x.at(1) = 6 * 9;
x.at(2) = 3.14;
CHECK_UNARY(x.at(0).is_boolean());
CHECK_UNARY(x.at(1).is_integer());
CHECK_UNARY(x.at(2).is_floating());
CHECK_EQ(x.at(0).as_boolean(), false);
CHECK_EQ(x.at(1).as_integer(), 6*9);
CHECK_EQ(x.at(2).as_floating(), 3.14);
x.at(0) = true;
x.at(1) = 42;
x.at(2) = "hoge";
// try_at
CHECK_UNARY(x.try_at(0).is_ok());
CHECK_UNARY(x.try_at(1).is_ok());
CHECK_UNARY(x.try_at(2).is_ok());
CHECK_UNARY(x.try_at(0).as_ok().is_boolean());
CHECK_UNARY(x.try_at(1).as_ok().is_integer());
CHECK_UNARY(x.try_at(2).as_ok().is_string());
CHECK_UNARY_FALSE(x.try_at(0).is_err());
CHECK_UNARY_FALSE(x.try_at(1).is_err());
CHECK_UNARY_FALSE(x.try_at(2).is_err());
CHECK_EQ(x.try_at(0).as_ok().as_boolean(), true);
CHECK_EQ(x.try_at(1).as_ok().as_integer(), 42);
CHECK_EQ(x.try_at(2).as_ok().as_string(), std::string("hoge"));
CHECK_UNARY(x.try_at(3).is_err());
CHECK_UNARY(as_const(x).try_at(0).is_ok());
CHECK_UNARY(as_const(x).try_at(1).is_ok());
CHECK_UNARY(as_const(x).try_at(2).is_ok());
CHECK_UNARY(as_const(x).try_at(0).as_ok().is_boolean());
CHECK_UNARY(as_const(x).try_at(1).as_ok().is_integer());
CHECK_UNARY(as_const(x).try_at(2).as_ok().is_string());
CHECK_UNARY_FALSE(as_const(x).try_at(0).is_err());
CHECK_UNARY_FALSE(as_const(x).try_at(1).is_err());
CHECK_UNARY_FALSE(as_const(x).try_at(2).is_err());
CHECK_EQ(as_const(x).try_at(0).as_ok().as_boolean(), true);
CHECK_EQ(as_const(x).try_at(1).as_ok().as_integer(), 42);
CHECK_EQ(as_const(x).try_at(2).as_ok().as_string(), std::string("hoge"));
CHECK_UNARY(as_const(x).try_at(3).is_err());
// update through try_at
x.try_at(0).as_ok() = false;
x.try_at(1).as_ok() = 6 * 9;
x.try_at(2).as_ok() = 3.14;
CHECK_UNARY(x.at(0).is_boolean());
CHECK_UNARY(x.at(1).is_integer());
CHECK_UNARY(x.at(2).is_floating());
CHECK_EQ(x.at(0).as_boolean(), false);
CHECK_EQ(x.at(1).as_integer(), 6*9);
CHECK_EQ(x.at(2).as_floating(), 3.14);
x.try_at(0).as_ok() = true;
x.try_at(1).as_ok() = 42;
x.try_at(2).as_ok() = "hoge";
// operator[]
CHECK_UNARY(x[0].is_boolean());
CHECK_UNARY(x[1].is_integer());
@@ -1086,6 +1154,8 @@ TEST_CASE("testing array-accessors")
CHECK_EQ(x[1].as_integer(), 42);
CHECK_EQ(x[2].as_string(), std::string("hoge"));
// -----------------------------------------------------------------------
const toml::value v1(3.14);
toml::value v2(2.71);
@@ -1143,13 +1213,83 @@ TEST_CASE("testing table-accessors")
CHECK_EQ(x.count("d"), 0);
CHECK_EQ(x.count("e"), 0);
// at
CHECK_UNARY(x.at("a").is_boolean());
CHECK_UNARY(x.at("b").is_integer());
CHECK_UNARY(x.at("c").is_string());
CHECK_EQ(x.at("a").as_boolean(), true);
CHECK_EQ(x.at("b").as_integer(), 42);
CHECK_EQ(x.at("c").as_string(), std::string("hoge"));
CHECK_THROWS_AS(x.at("d"), std::out_of_range);
CHECK_UNARY(as_const(x).at("a").is_boolean());
CHECK_UNARY(as_const(x).at("b").is_integer());
CHECK_UNARY(as_const(x).at("c").is_string());
CHECK_EQ(as_const(x).at("a").as_boolean(), true);
CHECK_EQ(as_const(x).at("b").as_integer(), 42);
CHECK_EQ(as_const(x).at("c").as_string(), std::string("hoge"));
CHECK_THROWS_AS(as_const(x).at("d"), std::out_of_range);
// rewrite using at
x.at("a") = false;
x.at("b") = 6*9;
x.at("c") = 3.14;
CHECK_UNARY(x.at("a").is_boolean());
CHECK_UNARY(x.at("b").is_integer());
CHECK_UNARY(x.at("c").is_floating());
CHECK_EQ(x.at("a").as_boolean(), false);
CHECK_EQ(x.at("b").as_integer(), 6*9);
CHECK_EQ(x.at("c").as_floating(), 3.14);
x.at("a") = true;
x.at("b") = 42;
x.at("c") = "hoge";
// try_at
CHECK_UNARY(x.try_at("a").is_ok());
CHECK_UNARY(x.try_at("b").is_ok());
CHECK_UNARY(x.try_at("c").is_ok());
CHECK_UNARY(x.try_at("a").as_ok().is_boolean());
CHECK_UNARY(x.try_at("b").as_ok().is_integer());
CHECK_UNARY(x.try_at("c").as_ok().is_string());
CHECK_EQ(x.try_at("a").as_ok().as_boolean(), true);
CHECK_EQ(x.try_at("b").as_ok().as_integer(), 42);
CHECK_EQ(x.try_at("c").as_ok().as_string(), std::string("hoge"));
CHECK_UNARY(x.try_at("d").is_err());
CHECK_UNARY(as_const(x).try_at("a").is_ok());
CHECK_UNARY(as_const(x).try_at("b").is_ok());
CHECK_UNARY(as_const(x).try_at("c").is_ok());
CHECK_UNARY(as_const(x).try_at("a").as_ok().is_boolean());
CHECK_UNARY(as_const(x).try_at("b").as_ok().is_integer());
CHECK_UNARY(as_const(x).try_at("c").as_ok().is_string());
CHECK_EQ(as_const(x).try_at("a").as_ok().as_boolean(), true);
CHECK_EQ(as_const(x).try_at("b").as_ok().as_integer(), 42);
CHECK_EQ(as_const(x).try_at("c").as_ok().as_string(), std::string("hoge"));
CHECK_UNARY(as_const(x).try_at("d").is_err());
// rewrite using try_at
x.try_at("a").as_ok() = false;
x.try_at("b").as_ok() = 6*9;
x.try_at("c").as_ok() = 3.14;
CHECK_UNARY(x.at("a").is_boolean());
CHECK_UNARY(x.at("b").is_integer());
CHECK_UNARY(x.at("c").is_floating());
CHECK_EQ(x.at("a").as_boolean(), false);
CHECK_EQ(x.at("b").as_integer(), 6*9);
CHECK_EQ(x.at("c").as_floating(), 3.14);
x.try_at("a").as_ok() = true;
x.try_at("b").as_ok() = 42;
x.try_at("c").as_ok() = "hoge";
// operator[]
CHECK_UNARY(x["a"].is_boolean());
CHECK_UNARY(x["b"].is_integer());