Compare commits

...

41 Commits

Author SHA1 Message Date
ToruNiina
1bf9e42835 chore: update version 2019-06-19 21:12:05 +09:00
ToruNiina
4a2c823d56 fix: comparison between values that has a table 2019-06-19 19:32:25 +09:00
ToruNiina
24c28c7f4f fix: correct some SFINAE expressions 2019-06-19 18:59:12 +09:00
ToruNiina
cab3144507 style: format CMakelists.txt 2019-06-19 16:53:45 +09:00
ToruNiina
dee32e7d5e style: make hint messages clearer 2019-06-19 12:58:34 +09:00
ToruNiina
53a185e7a9 fix: revert misjudgement as a bug
Probably I'm too tired.

This reverts commit adcd75e017.
2019-06-18 21:41:30 +09:00
ToruNiina
fd980a8c5d 🔀 Merge branch 'guess-type-error' 2019-06-18 21:29:45 +09:00
ToruNiina
73ac43d70c doc: add contributor 2019-06-18 21:28:50 +09:00
ToruNiina
adcd75e017 fix: correctly initialize offset 2019-06-18 21:27:16 +09:00
Toru Niina
569341a514 Merge pull request #69 from KerstinKeller/cmake_install
Allow to install toml11 library with CMake.
2019-06-17 18:03:00 +09:00
KerstinKeller
0357d8fb57 Add newline to end of CMake files. 2019-06-17 10:04:39 +02:00
ToruNiina
00d40140ac doc: add an example of error message to README 2019-06-17 12:59:29 +09:00
ToruNiina
1bfe8f1f54 Merge branch 'master' into guess-type-error 2019-06-17 12:48:36 +09:00
ToruNiina
bc143263cd Merge branch 'revert-recursive-find' 2019-06-17 11:54:52 +09:00
ToruNiina
1b19d5f1eb doc: update README 2019-06-16 21:44:59 +09:00
ToruNiina
fd7da05798 doc: update README 2019-06-16 20:31:08 +09:00
ToruNiina
cbaaaaca7c revert recursive find function
I found that in a user-code (I'm also one of the users of this library),
this new feature sometimes causes an error. Some of my code won't
compile because of this change. Since toml::table is convertible to
toml::value *implicitly*, if toml::find(table, key, tablename) was
called, the overload resolution becomes ambiguous with toml::find(
value, key1, key2). But dropping support for toml::find(toml::table,
key, tablename) is a breaking change. So I concluded that now is not
the right time yet.
2019-06-16 19:55:40 +09:00
ToruNiina
cf1c9371b6 fix: correct example and positions in err msgs 2019-06-16 17:52:42 +09:00
ToruNiina
62e8d58d8d feat: guess possible format errors 2019-06-16 17:32:29 +09:00
KerstinKeller
acbc2a73cb Allow to install tom11 library with CMake.
Add option to build tests.
2019-06-14 17:24:21 +02:00
ToruNiina
b2daf916b3 doc: add contributor to README 2019-06-11 22:45:46 +09:00
Toru Niina
e66bb3d359 Merge pull request #67 from ToruNiina/hotfix
suppress warnings on clang v7+
2019-06-10 10:54:54 +09:00
Toru Niina
cfaa94f072 Merge pull request #68 from khoitd1997/master
fix sign-compare warning
2019-06-10 10:49:49 +09:00
khoitd1997
2f4f3efbf0 fix sign-compare warning 2019-06-09 12:00:28 -07:00
ToruNiina
06ae67502a fix: move argument correctly 2019-06-09 21:05:46 +09:00
ToruNiina
57cb806e14 Merge branch 'master' into throw-from-as-something 2019-06-08 19:23:32 +09:00
ToruNiina
d6f3654185 refactor: reduce test code by using CHECK_THROW 2019-06-08 19:23:12 +09:00
ToruNiina
8befe3f1ad test: add test for throw/nothrow versions of as_* 2019-06-08 19:20:09 +09:00
ToruNiina
2d43119ac7 doc: change README a bit 2019-06-07 21:05:33 +09:00
ToruNiina
436af12815 doc: update README 2019-06-07 19:43:01 +09:00
ToruNiina
4f4d4380f2 feat: throw from as_* if type differs 2019-06-07 19:34:04 +09:00
ToruNiina
31debcb8aa 🔀 Merge branch 'master' into recursive-find 2019-06-07 19:02:20 +09:00
ToruNiina
2afa0ff0c3 doc: add find(value, key1, key2, ...) to README 2019-06-07 19:01:46 +09:00
ToruNiina
46047c48bf doc: add note about is|as_float to README 2019-06-07 13:40:21 +09:00
ToruNiina
897aecf5d4 test: avoid deprecated functions in the test codes 2019-06-07 13:32:02 +09:00
ToruNiina
7db8388d17 fix: avoid deprecated stuff in the internal code 2019-06-07 13:27:10 +09:00
ToruNiina
62c993e096 feat: add as|is_floating and deprecate as|is_float
to make the function names consistent with snake_case_typenames
2019-06-07 00:10:12 +09:00
ToruNiina
014d882f8f feat: enable to find value by recursive search 2019-06-07 00:06:14 +09:00
ToruNiina
2cbb93d86e fix: #65 Merge branch 'hotfix' 2019-06-03 21:27:25 +09:00
ToruNiina
a19b94511b fix: add space between operator"" and _toml
In C++11, it is required.
2019-06-03 20:58:35 +09:00
ToruNiina
70d0049511 refactor: move some meta-funcs to traits.hpp 2019-06-01 12:35:40 +09:00
13 changed files with 839 additions and 205 deletions

View File

@@ -1,7 +1,17 @@
cmake_minimum_required(VERSION 2.8)
enable_testing()
project(toml11)
set(toml11_VERSION_MAYOR 2)
set(toml11_VERSION_MINOR 4)
set(toml11_VERSION_PATCH 0)
set(toml11_VERSION
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
)
option(toml11_BUILD_TEST "Build toml tests" ON)
include(CheckCXXCompilerFlag)
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
set(CMAKE_CXX_EXTENSIONS OFF)
@@ -34,5 +44,62 @@ else()
endif()
endif()
include_directories(${PROJECT_SOURCE_DIR})
add_subdirectory(tests)
# Set some common directories
include(GNUInstallDirs)
set(toml11_install_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/toml11)
set(toml11_install_include_dir ${CMAKE_INSTALL_INCLUDEDIR})
set(toml11_config_dir ${CMAKE_CURRENT_BINARY_DIR}/cmake/)
set(toml11_config ${toml11_config_dir}/toml11Config.cmake)
set(toml11_config_version ${toml11_config_dir}/toml11ConfigVersion.cmake)
add_library(toml11 INTERFACE)
target_include_directories(toml11 INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${toml11_install_include_dir}>
)
add_library(toml11::toml11 ALIAS toml11)
# Write config and version config files
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${toml11_config_version}
VERSION ${toml11_VERSION}
COMPATIBILITY SameMajorVersion
)
configure_package_config_file(
cmake/toml11Config.cmake.in
${toml11_config}
INSTALL_DESTINATION ${toml11_install_cmake_dir}
PATH_VARS toml11_install_cmake_dir
)
# Install config files
install(FILES ${toml11_config} ${toml11_config_version}
DESTINATION ${toml11_install_cmake_dir}
)
# Install header files
install(
FILES toml.hpp
DESTINATION "${toml11_install_include_dir}"
)
install(
DIRECTORY "toml"
DESTINATION "${toml11_install_include_dir}"
FILES_MATCHING PATTERN "*.hpp"
)
# Export targets and install them
install(TARGETS toml11
EXPORT toml11Targets
)
install(EXPORT toml11Targets
FILE toml11Targets.cmake
DESTINATION ${toml11_install_cmake_dir}
NAMESPACE toml11::
)
if (toml11_BUILD_TEST)
add_subdirectory(tests)
endif ()

183
README.md
View File

@@ -144,6 +144,24 @@ terminate called after throwing an instance of 'toml::syntax_error'
| ~~~~~~~ table defined twice
```
When toml11 encounters a malformed value, it tries to detect what type it is.
Then it shows hints to fix the format. An error message while reading one of
the malformed files in [the language agnostic test suite](https://github.com/BurntSushi/toml-test).
is shown below.
```console
what(): [error] bad time: should be HH:MM:SS.subsec
--> ./datetime-malformed-no-secs.toml
1 | no-secs = 1987-07-05T17:45Z
| ^------- HH:MM:SS.subsec
|
Hint: pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999
Hint: fail: 1979-05-27T7:32:00, 1979-05-27 17:32
```
You can find other examples in a job named `output_result` on
[CircleCI](https://circleci.com/gh/ToruNiina/toml11).
Since the error message generation is generally a difficult task, the current
status is not ideal. If you encounter a weird error message, please let us know
and contribute to improve the quality!
@@ -425,6 +443,10 @@ toml::integer opt = 42;
toml::integer& i = toml::get_or(v, opt); // this works.
```
There is also a function `find_or`, but there is a known issue around overload
resolution. To use it, passing a `toml::value`, not a `toml::table`, is strongly
recommended.
## Expecting conversion
By using `toml::expect`, you will get your expected value or an error message
@@ -451,36 +473,20 @@ const auto value = toml::expect<int>(data.at("number"))
## Finding a value from a table
toml11 provides utility function to find a value from `toml::table`.
Of course, you can do this in your own way with `toml::get` because
it just searches an `unordered_map` and returns a value if it exists.
toml11 provides a utility function to find a value from `toml::value` and `toml::table`.
```cpp
const auto data = toml::parse("example.toml");
const auto num = toml::find<int>(data, "num", /*for err msg*/"example.toml");
const toml::value data = /* ... */;
// find a value named "num" from `data`.
const auto num = toml::find<int>(data, "num");
```
If the value does not exist, it throws `std::out_of_range` with an error message.
When you pass a `toml::value`, `toml::find` first casts it to `toml::table`.
If casting failed, `toml::type_error` will be thrown.
```console
terminate called after throwing an instance of 'std::out_of_range'
what(): [error] key "num" not found in example.toml
```
You can use this with a `toml::value` that is expected to be a `toml::table`.
It automatically casts the value to table.
```cpp
const auto data = toml::parse("example.toml");
const auto num = toml::find<int>(data.at("table"), "num");
// expecting the following example.toml
// [table]
// num = 42
```
In this case, because the value `data.at("table")` knows the locatoin of itself,
you don't need to pass where you find the value.
`toml::find` will show you an error message including table location.
When the value does not exist, it throws `std::out_of_range` with an error message.
By passing a `toml::value`, it shows an informative error message like the following.
```console
terminate called after throwing an instance of 'std::out_of_range'
@@ -490,17 +496,36 @@ terminate called after throwing an instance of 'std::out_of_range'
| ~~~~~~~ in this table
```
If it's not a `toml::table`, the same error as "invalid type" would be thrown.
There is another utility function, `toml::find_or`.
It is almost same as `toml::find`, but returns a default value if the value is
not found or has a different type, like `toml::get_or`.
Contrary, since `toml::table` is just an alias of `std::unordered_map<toml::key, toml::value>`,
you need to pass a name to the function to show the name in the exception with `toml::table`.
```cpp
const auto data = toml::parse("example.toml");
const auto num = toml::find_or(data.at("table"), "num", 42);
const toml::table data = /* ... */;
// you need to pass the name of the table to show it in an error message
const auto num = toml::find<int>(data, "num", "[data]");
```
```console
terminate called after throwing an instance of 'std::out_of_range'
what(): [error] key "num" not found in [data]
# table name is needed to show this part ^^^^^^
```
By default (w/o template parameter), `toml::find` returns a `toml::value`.
```cpp
const toml::value& subtable = toml::find(table, "subtable");
```
__NOTE__:
A new feature, recursive toml::find was planned to be introduced, but it was
found that the change breaks a code that was previously compiled fine. So the
change was reverted.
The reason is that the overload resolution was ambiguous. To support this,
in the next major update, overloads of `toml::find` for `toml::table` possibly
be removed.
## Checking value type
You can check what type of value does `toml::value` contains by `is_*` function.
@@ -516,20 +541,27 @@ if(v.is_integer())
The complete list of the functions is below.
```cpp
const toml::value v(/*...*/);
v.is_boolean();
v.is_integer();
v.is_float();
v.is_string();
v.is_offset_datetime();
v.is_local_datetime();
v.is_local_date();
v.is_local_time();
v.is_array();
v.is_table();
v.is_uninitialized();
namespace toml {
class value {
// ...
bool is_boolean() const noexcept;
bool is_integer() const noexcept;
bool is_floating() const noexcept;
bool is_string() const noexcept;
bool is_offset_datetime() const noexcept;
bool is_local_datetime() const noexcept;
bool is_local_date() const noexcept;
bool is_local_time() const noexcept;
bool is_array() const noexcept;
bool is_table() const noexcept;
bool is_uninitialized() const noexcept;
// ...
};
} // toml
```
__NOTE__: `is_float` is marked as deprecated since v2.4.0 to make the function names consistent with snake case typenames. Please use `is_floating` instead.
Also, you can get `enum class` value from `toml::value`.
```cpp
@@ -566,23 +598,56 @@ if(v.is_integer() && v.as_integer() == 42)
}
```
The complete list of the functions is below.
`as_*` functions internally checks the current contained type for safety and
throws `toml::type_error` if the contained value type is different (after toml11
v2.4.0). If you already confirmed that the value has the type you will cast
into, you can skip the additional checking by passing `std::nothrow` object to it.
```cpp
const toml::value v(/*...*/);
v.as_boolean();
v.as_integer();
v.as_float();
v.as_string();
v.as_offset_datetime();
v.as_local_datetime();
v.as_local_date();
v.as_local_time();
v.as_array();
v.as_table();
v.as_uninitialized();
toml::value v = /* ... */;
if(v.is_integer() && v.as_integer(std::nothrow) == 42) // never fail
{
std::cout << "value is 42" << std::endl;
}
```
The full list of the functions is below.
```cpp
namespace toml {
class value {
// ...
const boolean& as_boolean() const&;
const integer& as_integer() const&;
const floating& as_floating() const&;
const string& as_string() const&;
const offset_datetime& as_offset_datetime() const&;
const local_datetime& as_local_datetime() const&;
const local_date& as_local_date() const&;
const local_time& as_local_time() const&;
const array& as_array() const&;
const table& as_table() const&;
// --------------------------------------------------------
// non-const version
boolean& as_boolean() &;
// ditto...
// --------------------------------------------------------
// rvalue version
boolean&& as_boolean() &&;
// ditto...
// --------------------------------------------------------
// noexcept versions ...
const boolean& as_boolean(const std::nothrow_t&) const& noexcept;
boolean& as_boolean(const std::nothrow_t&) & noexcept;
boolean&& as_boolean(const std::nothrow_t&) && noexcept;
// ditto...
};
} // toml
```
__NOTE__: `as_float` is marked as deprecated since v2.4.0 to make the function names consistent with snake case typenames. Please use `as_floating` instead.
## Visiting a toml::value
toml11 provides `toml::visit` to apply a function to `toml::value` in the
@@ -1070,6 +1135,10 @@ I appreciate the help of the contributors who introduced the great feature to th
- Fixed warnings on MSVC
- Ivan Shynkarenka (@chronoxor)
- Fixed Visual Studio 2019 warnings
- @khoitd1997
- Fixed warnings while type conversion
- @KerstinKeller
- Added installation script to CMake
## Licensing terms

View File

@@ -0,0 +1,2 @@
@PACKAGE_INIT@
include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake")

View File

@@ -88,7 +88,7 @@ add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
foreach(TEST_NAME ${TEST_NAMES})
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
@@ -105,3 +105,4 @@ endforeach(TEST_NAME)
add_executable(test_multiple_translation_unit
test_multiple_translation_unit_1.cpp
test_multiple_translation_unit_2.cpp)
target_link_libraries(test_multiple_translation_unit toml11::toml11)

View File

@@ -78,8 +78,8 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
const toml::value v1 = u8"3.1415"_toml;
const toml::value v2 = u8"6.02e+23"_toml;
BOOST_CHECK(v1.is_float());
BOOST_CHECK(v2.is_float());
BOOST_CHECK(v1.is_floating());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_CLOSE(toml::get<double>(v1), 3.1415, 0.00001);
BOOST_CHECK_CLOSE(toml::get<double>(v2), 6.02e23, 0.0001);
}

View File

@@ -32,6 +32,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
BOOST_CHECK_EQUAL(v2.as_boolean(), false);
BOOST_CHECK_EQUAL(v1.as_boolean(std::nothrow), true);
BOOST_CHECK_EQUAL(v2.as_boolean(std::nothrow), false);
v1 = false;
v2 = true;
@@ -96,12 +98,12 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
BOOST_CHECK(v1.is<toml::Integer>());
BOOST_CHECK(v2.is<toml::Float>());
BOOST_CHECK(v1.is_integer());
BOOST_CHECK(v2.is_float());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 42);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_EQUAL(v1.as_integer(), 42);
BOOST_CHECK_EQUAL(v2.as_float(), 3.14);
BOOST_CHECK_EQUAL(v2.as_floating(), 3.14);
}
BOOST_AUTO_TEST_CASE(test_value_integer)
@@ -122,6 +124,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
BOOST_CHECK_EQUAL(v1.as_integer(), -42);
BOOST_CHECK_EQUAL(v2.as_integer(), 42u);
BOOST_CHECK_EQUAL(v1.as_integer(std::nothrow), -42);
BOOST_CHECK_EQUAL(v2.as_integer(std::nothrow), 42u);
v1 = 54;
v2 = -54;
@@ -205,13 +209,15 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v2.is(toml::value_t::Float));
BOOST_CHECK(v1.is<toml::Float>());
BOOST_CHECK(v2.is<toml::Float>());
BOOST_CHECK(v1.is_float());
BOOST_CHECK(v2.is_float());
BOOST_CHECK(v1.is_floating());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_EQUAL (v1.cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
BOOST_CHECK_EQUAL (v1.as_float(), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.as_float(), 3.14, 1e-2);
BOOST_CHECK_EQUAL (v1.as_floating(), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(), 3.14, 1e-2);
BOOST_CHECK_EQUAL (v1.as_floating(std::nothrow), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(std::nothrow), 3.14, 1e-2);
v1 = 2.718f;
v2 = 2.718;
@@ -222,13 +228,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v2.is(toml::value_t::Float));
BOOST_CHECK(v1.is<toml::Float>());
BOOST_CHECK(v2.is<toml::Float>());
BOOST_CHECK(v1.is_float());
BOOST_CHECK(v2.is_float());
BOOST_CHECK(v1.is_floating());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_CLOSE_FRACTION(v1.cast<toml::value_t::Float>(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v2.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v1.as_float(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v2.as_float(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v1.as_floating(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v2.as_floating(), 2.718);
toml::value v3(v1);
toml::value v4(v2);
@@ -241,13 +247,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v4.is(toml::value_t::Float));
BOOST_CHECK(v3.is<toml::Float>());
BOOST_CHECK(v4.is<toml::Float>());
BOOST_CHECK(v3.is_float());
BOOST_CHECK(v4.is_float());
BOOST_CHECK(v3.is_floating());
BOOST_CHECK(v4.is_floating());
BOOST_CHECK_CLOSE_FRACTION(v3.cast<toml::value_t::Float>(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v4.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v3.as_float(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v4.as_float(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v3.as_floating(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v4.as_floating(), 2.718);
toml::value v5(std::move(v1));
toml::value v6(std::move(v2));
@@ -258,13 +264,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v6.is(toml::value_t::Float));
BOOST_CHECK(v5.is<toml::Float>());
BOOST_CHECK(v6.is<toml::Float>());
BOOST_CHECK(v5.is_float());
BOOST_CHECK(v6.is_float());
BOOST_CHECK(v5.is_floating());
BOOST_CHECK(v6.is_floating());
BOOST_CHECK_CLOSE_FRACTION(v5.cast<toml::value_t::Float>(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v6.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v5.as_float(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v6.as_float(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v5.as_floating(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v6.as_floating(), 2.718);
v1 = true;
v2 = false;
@@ -309,7 +315,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
BOOST_CHECK_EQUAL(v1.as_string(), "foo");
BOOST_CHECK_EQUAL(v2.as_string(), "foo");
BOOST_CHECK_EQUAL(v3.as_string(), "foo");
BOOST_CHECK_EQUAL(v1.as_string(std::nothrow), "foo");
BOOST_CHECK_EQUAL(v2.as_string(std::nothrow), "foo");
BOOST_CHECK_EQUAL(v3.as_string(std::nothrow), "foo");
v1 = "bar";
v2 = "bar";
@@ -439,6 +447,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
toml::local_date(2018, toml::month_t::Jan, 31));
BOOST_CHECK_EQUAL(v1.as_local_date(),
toml::local_date(2018, toml::month_t::Jan, 31));
BOOST_CHECK_EQUAL(v1.as_local_date(std::nothrow),
toml::local_date(2018, toml::month_t::Jan, 31));
v1 = toml::local_date(2018, toml::month_t::Apr, 1);
@@ -503,6 +513,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
v2.cast<toml::value_t::LocalTime>());
BOOST_CHECK_EQUAL(v1.as_local_time(),
v2.as_local_time());
BOOST_CHECK_EQUAL(v1.as_local_time(std::nothrow),
v2.as_local_time(std::nothrow));
v1 = toml::local_time(1, 30, 0, /*ms*/ 100, /*us*/ 0);
@@ -557,6 +569,11 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
toml::local_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45)));
BOOST_CHECK_EQUAL(v1.as_local_datetime(std::nothrow),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45)));
v1 = toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
@@ -628,6 +645,13 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
toml::local_time(12, 30, 45),
toml::time_offset(9, 0)
));
BOOST_CHECK_EQUAL(v1.as_offset_datetime(std::nothrow),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45),
toml::time_offset(9, 0)
));
v1 = toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
@@ -705,7 +729,11 @@ BOOST_AUTO_TEST_CASE(test_value_array)
BOOST_CHECK_EQUAL(v1.as_array().at(2).as_integer(), 3);
BOOST_CHECK_EQUAL(v1.as_array().at(3).as_integer(), 4);
BOOST_CHECK_EQUAL(v1.as_array().at(4).as_integer(), 5);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(0).as_integer(), 1);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(1).as_integer(), 2);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(2).as_integer(), 3);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(3).as_integer(), 4);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(4).as_integer(), 5);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
@@ -792,8 +820,11 @@ BOOST_AUTO_TEST_CASE(test_value_table)
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "qux");
BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_integer(), 42);
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_float(), 3.14);
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_floating(), 3.14);
BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "qux");
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("foo").as_integer(), 42);
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("bar").as_floating(), 3.14);
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("baz").as_string().str, "qux");
v1 = toml::table{{"foo", 2.71}, {"bar", 54}, {"baz", "quux"}};
@@ -806,7 +837,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "quux");
BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_float(), 2.71);
BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_floating(), 2.71);
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_integer(), 54);
BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "quux");
@@ -822,7 +853,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "quux");
BOOST_CHECK_EQUAL(v3.as_table().at("foo").as_float(), 2.71);
BOOST_CHECK_EQUAL(v3.as_table().at("foo").as_floating(), 2.71);
BOOST_CHECK_EQUAL(v3.as_table().at("bar").as_integer(), 54);
BOOST_CHECK_EQUAL(v3.as_table().at("baz").as_string().str, "quux");
@@ -841,4 +872,15 @@ BOOST_AUTO_TEST_CASE(test_value_empty)
toml::value v1;
BOOST_CHECK(v1.is_uninitialized());
BOOST_CHECK(v1.is(toml::value_t::Empty));
BOOST_CHECK_THROW(v1.as_boolean(), toml::type_error);
BOOST_CHECK_THROW(v1.as_integer(), toml::type_error);
BOOST_CHECK_THROW(v1.as_floating(), toml::type_error);
BOOST_CHECK_THROW(v1.as_string(), toml::type_error);
BOOST_CHECK_THROW(v1.as_offset_datetime(), toml::type_error);
BOOST_CHECK_THROW(v1.as_local_datetime(), toml::type_error);
BOOST_CHECK_THROW(v1.as_local_date(), toml::type_error);
BOOST_CHECK_THROW(v1.as_local_time(), toml::type_error);
BOOST_CHECK_THROW(v1.as_array(), toml::type_error);
BOOST_CHECK_THROW(v1.as_table(), toml::type_error);
}

View File

@@ -45,7 +45,7 @@ inline std::string show_char(const char c)
buf.fill('\0');
const auto r = std::snprintf(
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
assert(r == buf.size() - 1);
assert(r == static_cast<int>(buf.size()) - 1);
return std::string(buf.data());
}
}

View File

@@ -519,7 +519,7 @@ std::string get_or(toml::value&& v, T&& opt)
}
catch(...)
{
return opt;
return std::forward<T>(opt);
}
}
template<typename T, typename std::enable_if<
@@ -541,9 +541,12 @@ std::string get_or(const toml::value& v, T&& opt)
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>,
detail::negation<std::is_same<T, std::string>>,
detail::negation<detail::is_string_literal<typename std::remove_reference<T>::type>>
detail::negation<detail::is_exact_toml_type<
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<std::is_same<std::string,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<detail::is_string_literal<
typename std::remove_reference<T>::type>>
>::value, std::nullptr_t>::type = nullptr>
T get_or(const toml::value& v, T&& opt)
{
@@ -554,7 +557,7 @@ T get_or(const toml::value& v, T&& opt)
}
catch(...)
{
return opt;
return T(std::move(opt));
}
}
@@ -617,9 +620,9 @@ template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string find_or(toml::value&& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return opt;}
if(!v.is_table()) {return std::forward<T>(opt);}
auto tab = toml::get<toml::table>(std::move(v));
if(tab.count(ky) == 0) {return opt;}
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
@@ -639,9 +642,12 @@ std::string find_or(const toml::value& v, const toml::key& ky, T&& opt)
// ---------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>,
detail::negation<std::is_same<T, std::string>>,
detail::negation<detail::is_string_literal<typename std::remove_reference<T>::type>>
detail::negation<detail::is_exact_toml_type<
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<std::is_same<std::string,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<detail::is_string_literal<
typename std::remove_reference<T>::type>>
>::value, std::nullptr_t>::type = nullptr>
T find_or(const toml::value& v, const toml::key& ky, T&& opt)
{
@@ -651,8 +657,8 @@ T find_or(const toml::value& v, const toml::key& ky, T&& opt)
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ===========================================================================
// find_or(table, key, opt)
// ---------------------------------------------------------------------------
// toml::find(table)
// ---------------------------------------------------------------------------
// exact types (return type can be a reference)
@@ -700,7 +706,7 @@ template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string find_or(toml::table&& tab, const toml::key& ky, T&& opt)
{
if(tab.count(ky) == 0) {return opt;}
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
@@ -718,9 +724,12 @@ std::string find_or(const toml::table& tab, const toml::key& ky, T&& opt)
// ---------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>,
detail::negation<std::is_same<T, std::string>>,
detail::negation<detail::is_string_literal<typename std::remove_reference<T>::type>>
detail::negation<detail::is_exact_toml_type<
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<std::is_same<std::string,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<detail::is_string_literal<
typename std::remove_reference<T>::type>>
>::value, std::nullptr_t>::type = nullptr>
T find_or(const toml::table& tab, const toml::key& ky, T&& opt)
{

View File

@@ -11,7 +11,7 @@ inline namespace literals
inline namespace toml_literals
{
inline ::toml::value operator""_toml(const char* str, std::size_t len)
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
{
::toml::detail::location<std::vector<char>>
loc(/* filename = */ std::string("TOML literal encoded in a C++ code"),

View File

@@ -1410,41 +1410,156 @@ parse_inline_table(location<Container>& loc)
}
template<typename Container>
value_t guess_number_type(const location<Container>& l)
result<value_t, std::string> guess_number_type(const location<Container>& l)
{
// This function tries to find some (common) mistakes by checking characters
// that follows the last character of a value. But it is often difficult
// because some non-newline characters can appear after a value. E.g.
// spaces, tabs, commas (in an array or inline table), closing brackets
// (of an array or inline table), comment-sign (#). Since this function
// does not parse further, those characters are always allowed to be there.
location<Container> loc = l;
if(lex_offset_date_time::invoke(loc)) {return value_t::OffsetDatetime;}
if(lex_offset_date_time::invoke(loc)) {return ok(value_t::OffsetDatetime);}
loc.reset(l.iter());
if(lex_local_date_time::invoke(loc)) {return value_t::LocalDatetime;}
if(lex_local_date_time::invoke(loc))
{
// bad offset may appear after this.
if(loc.iter() != loc.end() && (*loc.iter() == '+' || *loc.iter() == '-'
|| *loc.iter() == 'Z' || *loc.iter() == 'z'))
{
return err(format_underline("[error] bad offset: should be [+-]HH:MM or Z",
{{std::addressof(loc), "[+-]HH:MM or Z"}},
{"pass: +09:00, -05:30", "fail: +9:00, -5:30"}));
}
return ok(value_t::LocalDatetime);
}
loc.reset(l.iter());
if(lex_local_date::invoke(loc)) {return value_t::LocalDate;}
if(lex_local_date::invoke(loc))
{
// bad time may appear after this.
// A space is allowed as a delimiter between local time. But there are
// both cases in which a space becomes valid or invalid.
// - invalid: 2019-06-16 7:00:00
// - valid : 2019-06-16 07:00:00
if(loc.iter() != loc.end())
{
const auto c = *loc.iter();
if(c == 'T' || c == 't')
{
return err(format_underline("[error] bad time: should be HH:MM:SS.subsec",
{{std::addressof(loc), "HH:MM:SS.subsec"}},
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
"fail: 1979-05-27T7:32:00, 1979-05-27 17:32"}));
}
if('0' <= c && c <= '9')
{
return err(format_underline("[error] bad time: missing T",
{{std::addressof(loc), "T or space required here"}},
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
"fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
}
if(c == ' ' && std::next(loc.iter()) != loc.end() &&
('0' <= *std::next(loc.iter()) && *std::next(loc.iter())<= '9'))
{
loc.advance();
return err(format_underline("[error] bad time: should be HH:MM:SS.subsec",
{{std::addressof(loc), "HH:MM:SS.subsec"}},
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
"fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
}
}
return ok(value_t::LocalDate);
}
loc.reset(l.iter());
if(lex_local_time::invoke(loc)) {return value_t::LocalTime;}
if(lex_local_time::invoke(loc)) {return ok(value_t::LocalTime);}
loc.reset(l.iter());
if(lex_float::invoke(loc)) {return value_t::Float;}
if(lex_float::invoke(loc))
{
if(loc.iter() != loc.end() && *loc.iter() == '_')
{
return err(format_underline("[error] bad float: `_` should be surrounded by digits",
{{std::addressof(loc), "here"}},
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
}
return ok(value_t::Float);
}
loc.reset(l.iter());
return value_t::Integer;
if(lex_integer::invoke(loc))
{
if(loc.iter() != loc.end())
{
const auto c = *loc.iter();
if(c == '_')
{
return err(format_underline("[error] bad integer: `_` should be surrounded by digits",
{{std::addressof(loc), "here"}},
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
"fail: 1__000, 0123"}));
}
if('0' <= c && c <= '9')
{
// leading zero. point '0'
loc.retrace();
return err(format_underline("[error] bad integer: leading zero",
{{std::addressof(loc), "here"}},
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
"fail: 1__000, 0123"}));
}
if(c == ':' || c == '-')
{
return err(format_underline("[error] bad datetime: invalid format",
{{std::addressof(loc), "here"}},
{"pass: 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z",
"fail: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30"}));
}
if(c == '.' || c == 'e' || c == 'E')
{
return err(format_underline("[error] bad float: invalid format",
{{std::addressof(loc), "here"}},
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
}
}
return ok(value_t::Integer);
}
if(loc.iter() != loc.end() && *loc.iter() == '.')
{
return err(format_underline("[error] bad float: invalid format",
{{std::addressof(loc), "integer part required before this"}},
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
}
if(loc.iter() != loc.end() && *loc.iter() == '_')
{
return err(format_underline("[error] bad number: `_` should be surrounded by digits",
{{std::addressof(loc), "`_` is not surrounded by digits"}},
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
"fail: 1__000, 0123"}));
}
return err(format_underline("[error] bad format: unknown value appeared",
{{std::addressof(loc), "here"}}));
}
template<typename Container>
value_t guess_value_type(const location<Container>& loc)
result<value_t, std::string> guess_value_type(const location<Container>& loc)
{
switch(*loc.iter())
{
case '"' : {return value_t::String; }
case '\'': {return value_t::String; }
case 't' : {return value_t::Boolean;}
case 'f' : {return value_t::Boolean;}
case '[' : {return value_t::Array; }
case '{' : {return value_t::Table; }
case 'i' : {return value_t::Float; } // inf.
case 'n' : {return value_t::Float; } // nan.
case '"' : {return ok(value_t::String); }
case '\'': {return ok(value_t::String); }
case 't' : {return ok(value_t::Boolean);}
case 'f' : {return ok(value_t::Boolean);}
case '[' : {return ok(value_t::Array); }
case '{' : {return ok(value_t::Table); }
case 'i' : {return ok(value_t::Float); } // inf.
case 'n' : {return ok(value_t::Float); } // nan.
default : {return guess_number_type(loc);}
}
}
@@ -1459,7 +1574,12 @@ result<value, std::string> parse_value(location<Container>& loc)
{{std::addressof(loc), ""}}));
}
switch(guess_value_type(loc))
const auto type = guess_value_type(loc);
if(!type)
{
return err(type.unwrap_err());
}
switch(type.unwrap())
{
case value_t::Boolean : {return parse_boolean(loc); }
case value_t::Integer : {return parse_integer(loc); }

View File

@@ -6,6 +6,12 @@
#include <utility>
#include <chrono>
#include <tuple>
#include <string>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus >= C++17
namespace toml
{
@@ -81,7 +87,6 @@ struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T>(nullptr)){};
@@ -114,7 +119,7 @@ template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
// ---------------------------------------------------------------------------
// normal type checker
// type checkers
template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
@@ -128,6 +133,33 @@ template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
has_iterator<T>, // has T::iterator
has_value_type<T>, // has T::value_type
has_key_type<T>, // has T::key_type
has_mapped_type<T> // has T::mapped_type
>{};
template<typename T> struct is_map<T&> : is_map<T>{};
template<typename T> struct is_map<T const&> : is_map<T>{};
template<typename T> struct is_map<T volatile&> : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
template<typename T>
struct is_container : conjunction<
negation<is_map<T>>, // not a map
negation<std::is_same<T, std::string>>, // not a std::string
#if __cplusplus >= 201703L
negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
has_iterator<T>, // has T::iterator
has_value_type<T> // has T::value_type
>{};
template<typename T> struct is_container<T&> : is_container<T>{};
template<typename T> struct is_container<T const&> : is_container<T>{};
template<typename T> struct is_container<T volatile&> : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
// ---------------------------------------------------------------------------
// C++14 index_sequence

View File

@@ -7,11 +7,6 @@
#include "traits.hpp"
#include <vector>
#include <unordered_map>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif
#endif
namespace toml
{
@@ -161,34 +156,6 @@ template<typename T> struct is_exact_toml_type<T const&> : is_exact_toml
template<typename T> struct is_exact_toml_type<T volatile&> : is_exact_toml_type<T>{};
template<typename T> struct is_exact_toml_type<T const volatile&>: is_exact_toml_type<T>{};
template<typename T>
struct is_map : conjunction<
has_iterator<T>,
has_value_type<T>,
has_key_type<T>,
has_mapped_type<T>
>{};
template<typename T> struct is_map<T&> : is_map<T>{};
template<typename T> struct is_map<T const&> : is_map<T>{};
template<typename T> struct is_map<T volatile&> : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
template<typename T>
struct is_container : conjunction<
negation<is_map<T>>,
negation<std::is_same<T, std::string>>,
#if __cplusplus >= 201703L
negation<std::is_same<T, std::string_view>>,
#endif
has_iterator<T>,
has_value_type<T>
>{};
template<typename T> struct is_container<T&> : is_container<T>{};
template<typename T> struct is_container<T const&> : is_container<T>{};
template<typename T> struct is_container<T volatile&> : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
} // detail
} // toml
#endif// TOML11_TYPES_H

View File

@@ -27,6 +27,16 @@ namespace detail
region_base const& get_region(const value&);
template<typename Region>
void change_region(value&, Region&&);
template<value_t Expected>
[[noreturn]] inline void throw_bad_cast(value_t actual, const ::toml::value& v)
{
throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", Expected), {
{std::addressof(get_region(v)),
concat_to_string("the actual type is ", actual)}
}));
}
}// detail
template<typename T>
@@ -616,7 +626,7 @@ class value
bool is_uninitialized() const noexcept {return this->is(value_t::Empty );}
bool is_boolean() const noexcept {return this->is(value_t::Boolean );}
bool is_integer() const noexcept {return this->is(value_t::Integer );}
bool is_float() const noexcept {return this->is(value_t::Float );}
bool is_floating() const noexcept {return this->is(value_t::Float );}
bool is_string() const noexcept {return this->is(value_t::String );}
bool is_offset_datetime() const noexcept {return this->is(value_t::OffsetDatetime);}
bool is_local_datetime() const noexcept {return this->is(value_t::LocalDatetime );}
@@ -634,38 +644,353 @@ class value
template<value_t T>
typename detail::toml_default_type<T>::type&& cast() &&;
boolean const& as_boolean() const& noexcept {return this->boolean_;}
integer const& as_integer() const& noexcept {return this->integer_;}
floating const& as_float() const& noexcept {return this->floating_;}
string const& as_string() const& noexcept {return this->string_;}
offset_datetime const& as_offset_datetime() const& noexcept {return this->offset_datetime_;}
local_datetime const& as_local_datetime() const& noexcept {return this->local_datetime_;}
local_date const& as_local_date() const& noexcept {return this->local_date_;}
local_time const& as_local_time() const& noexcept {return this->local_time_;}
array const& as_array() const& noexcept {return this->array_.value();}
table const& as_table() const& noexcept {return this->table_.value();}
// ------------------------------------------------------------------------
// nothrow version
boolean & as_boolean() & noexcept {return this->boolean_;}
integer & as_integer() & noexcept {return this->integer_;}
floating & as_float() & noexcept {return this->floating_;}
string & as_string() & noexcept {return this->string_;}
offset_datetime& as_offset_datetime() & noexcept {return this->offset_datetime_;}
local_datetime & as_local_datetime() & noexcept {return this->local_datetime_;}
local_date & as_local_date() & noexcept {return this->local_date_;}
local_time & as_local_time() & noexcept {return this->local_time_;}
array & as_array() & noexcept {return this->array_.value();}
table & as_table() & noexcept {return this->table_.value();}
boolean const& as_boolean (const std::nothrow_t&) const& noexcept {return this->boolean_;}
integer const& as_integer (const std::nothrow_t&) const& noexcept {return this->integer_;}
floating const& as_floating (const std::nothrow_t&) const& noexcept {return this->floating_;}
string const& as_string (const std::nothrow_t&) const& noexcept {return this->string_;}
offset_datetime const& as_offset_datetime(const std::nothrow_t&) const& noexcept {return this->offset_datetime_;}
local_datetime const& as_local_datetime (const std::nothrow_t&) const& noexcept {return this->local_datetime_;}
local_date const& as_local_date (const std::nothrow_t&) const& noexcept {return this->local_date_;}
local_time const& as_local_time (const std::nothrow_t&) const& noexcept {return this->local_time_;}
array const& as_array (const std::nothrow_t&) const& noexcept {return this->array_.value();}
table const& as_table (const std::nothrow_t&) const& noexcept {return this->table_.value();}
boolean && as_boolean() && noexcept {return std::move(this->boolean_);}
integer && as_integer() && noexcept {return std::move(this->integer_);}
floating && as_float() && noexcept {return std::move(this->floating_);}
string && as_string() && noexcept {return std::move(this->string_);}
offset_datetime&& as_offset_datetime() && noexcept {return std::move(this->offset_datetime_);}
local_datetime && as_local_datetime() && noexcept {return std::move(this->local_datetime_);}
local_date && as_local_date() && noexcept {return std::move(this->local_date_);}
local_time && as_local_time() && noexcept {return std::move(this->local_time_);}
array && as_array() && noexcept {return std::move(this->array_.value());}
table && as_table() && noexcept {return std::move(this->table_.value());}
boolean & as_boolean (const std::nothrow_t&) & noexcept {return this->boolean_;}
integer & as_integer (const std::nothrow_t&) & noexcept {return this->integer_;}
floating & as_floating (const std::nothrow_t&) & noexcept {return this->floating_;}
string & as_string (const std::nothrow_t&) & noexcept {return this->string_;}
offset_datetime& as_offset_datetime(const std::nothrow_t&) & noexcept {return this->offset_datetime_;}
local_datetime & as_local_datetime (const std::nothrow_t&) & noexcept {return this->local_datetime_;}
local_date & as_local_date (const std::nothrow_t&) & noexcept {return this->local_date_;}
local_time & as_local_time (const std::nothrow_t&) & noexcept {return this->local_time_;}
array & as_array (const std::nothrow_t&) & noexcept {return this->array_.value();}
table & as_table (const std::nothrow_t&) & noexcept {return this->table_.value();}
boolean && as_boolean (const std::nothrow_t&) && noexcept {return std::move(this->boolean_);}
integer && as_integer (const std::nothrow_t&) && noexcept {return std::move(this->integer_);}
floating && as_floating (const std::nothrow_t&) && noexcept {return std::move(this->floating_);}
string && as_string (const std::nothrow_t&) && noexcept {return std::move(this->string_);}
offset_datetime&& as_offset_datetime(const std::nothrow_t&) && noexcept {return std::move(this->offset_datetime_);}
local_datetime && as_local_datetime (const std::nothrow_t&) && noexcept {return std::move(this->local_datetime_);}
local_date && as_local_date (const std::nothrow_t&) && noexcept {return std::move(this->local_date_);}
local_time && as_local_time (const std::nothrow_t&) && noexcept {return std::move(this->local_time_);}
array && as_array (const std::nothrow_t&) && noexcept {return std::move(this->array_.value());}
table && as_table (const std::nothrow_t&) && noexcept {return std::move(this->table_.value());}
// ========================================================================
// throw version
// ------------------------------------------------------------------------
// const reference
boolean const& as_boolean() const&
{
if(this->type_ != value_t::Boolean)
{
detail::throw_bad_cast<value_t::Boolean>(this->type_, *this);
}
return this->boolean_;
}
integer const& as_integer() const&
{
if(this->type_ != value_t::Integer)
{
detail::throw_bad_cast<value_t::Integer>(this->type_, *this);
}
return this->integer_;
}
floating const& as_floating() const&
{
if(this->type_ != value_t::Float)
{
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
}
return this->floating_;
}
string const& as_string() const&
{
if(this->type_ != value_t::String)
{
detail::throw_bad_cast<value_t::String>(this->type_, *this);
}
return this->string_;
}
offset_datetime const& as_offset_datetime() const&
{
if(this->type_ != value_t::OffsetDatetime)
{
detail::throw_bad_cast<value_t::OffsetDatetime>(this->type_, *this);
}
return this->offset_datetime_;
}
local_datetime const& as_local_datetime() const&
{
if(this->type_ != value_t::LocalDatetime)
{
detail::throw_bad_cast<value_t::LocalDatetime>(this->type_, *this);
}
return this->local_datetime_;
}
local_date const& as_local_date() const&
{
if(this->type_ != value_t::LocalDate)
{
detail::throw_bad_cast<value_t::LocalDate>(this->type_, *this);
}
return this->local_date_;
}
local_time const& as_local_time() const&
{
if(this->type_ != value_t::LocalTime)
{
detail::throw_bad_cast<value_t::LocalTime>(this->type_, *this);
}
return this->local_time_;
}
array const& as_array() const&
{
if(this->type_ != value_t::Array)
{
detail::throw_bad_cast<value_t::Array>(this->type_, *this);
}
return this->array_.value();
}
table const& as_table() const&
{
if(this->type_ != value_t::Table)
{
detail::throw_bad_cast<value_t::Table>(this->type_, *this);
}
return this->table_.value();
}
// ------------------------------------------------------------------------
// nonconst reference
boolean & as_boolean() &
{
if(this->type_ != value_t::Boolean)
{
detail::throw_bad_cast<value_t::Boolean>(this->type_, *this);
}
return this->boolean_;
}
integer & as_integer() &
{
if(this->type_ != value_t::Integer)
{
detail::throw_bad_cast<value_t::Integer>(this->type_, *this);
}
return this->integer_;
}
floating & as_floating() &
{
if(this->type_ != value_t::Float)
{
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
}
return this->floating_;
}
string & as_string() &
{
if(this->type_ != value_t::String)
{
detail::throw_bad_cast<value_t::String>(this->type_, *this);
}
return this->string_;
}
offset_datetime & as_offset_datetime() &
{
if(this->type_ != value_t::OffsetDatetime)
{
detail::throw_bad_cast<value_t::OffsetDatetime>(this->type_, *this);
}
return this->offset_datetime_;
}
local_datetime & as_local_datetime() &
{
if(this->type_ != value_t::LocalDatetime)
{
detail::throw_bad_cast<value_t::LocalDatetime>(this->type_, *this);
}
return this->local_datetime_;
}
local_date & as_local_date() &
{
if(this->type_ != value_t::LocalDate)
{
detail::throw_bad_cast<value_t::LocalDate>(this->type_, *this);
}
return this->local_date_;
}
local_time & as_local_time() &
{
if(this->type_ != value_t::LocalTime)
{
detail::throw_bad_cast<value_t::LocalTime>(this->type_, *this);
}
return this->local_time_;
}
array & as_array() &
{
if(this->type_ != value_t::Array)
{
detail::throw_bad_cast<value_t::Array>(this->type_, *this);
}
return this->array_.value();
}
table & as_table() &
{
if(this->type_ != value_t::Table)
{
detail::throw_bad_cast<value_t::Table>(this->type_, *this);
}
return this->table_.value();
}
// ------------------------------------------------------------------------
// rvalue reference
boolean && as_boolean() &&
{
if(this->type_ != value_t::Boolean)
{
detail::throw_bad_cast<value_t::Boolean>(this->type_, *this);
}
return std::move(this->boolean_);
}
integer && as_integer() &&
{
if(this->type_ != value_t::Integer)
{
detail::throw_bad_cast<value_t::Integer>(this->type_, *this);
}
return std::move(this->integer_);
}
floating && as_floating() &&
{
if(this->type_ != value_t::Float)
{
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
}
return std::move(this->floating_);
}
string && as_string() &&
{
if(this->type_ != value_t::String)
{
detail::throw_bad_cast<value_t::String>(this->type_, *this);
}
return std::move(this->string_);
}
offset_datetime && as_offset_datetime() &&
{
if(this->type_ != value_t::OffsetDatetime)
{
detail::throw_bad_cast<value_t::OffsetDatetime>(this->type_, *this);
}
return std::move(this->offset_datetime_);
}
local_datetime && as_local_datetime() &&
{
if(this->type_ != value_t::LocalDatetime)
{
detail::throw_bad_cast<value_t::LocalDatetime>(this->type_, *this);
}
return std::move(this->local_datetime_);
}
local_date && as_local_date() &&
{
if(this->type_ != value_t::LocalDate)
{
detail::throw_bad_cast<value_t::LocalDate>(this->type_, *this);
}
return std::move(this->local_date_);
}
local_time && as_local_time() &&
{
if(this->type_ != value_t::LocalTime)
{
detail::throw_bad_cast<value_t::LocalTime>(this->type_, *this);
}
return std::move(this->local_time_);
}
array && as_array() &&
{
if(this->type_ != value_t::Array)
{
detail::throw_bad_cast<value_t::Array>(this->type_, *this);
}
return std::move(this->array_.value());
}
table && as_table() &&
{
if(this->type_ != value_t::Table)
{
detail::throw_bad_cast<value_t::Table>(this->type_, *this);
}
return std::move(this->table_.value());
}
// ------------------------------------------------------------------------
// as|is_float (deprecated)
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
bool is_float() const noexcept {return this->is(value_t::Float);}
// ------------------------------------------------------------------------
// nothrow version
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating(std::nothrow) instead.")
floating& as_float(const std::nothrow_t&) & noexcept
{
return this->floating_;
}
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating(std::nothrow) instead.")
floating&& as_float(const std::nothrow_t&) && noexcept
{
return std::move(this->floating_);
}
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating(std::nothrow) instead.")
floating const& as_float(const std::nothrow_t&) const& noexcept
{
return this->floating_;
}
// ------------------------------------------------------------------------
// throw version
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
floating& as_float() &
{
if(this->type_ != value_t::Float)
{
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
}
return this->floating_;
}
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
floating&& as_float() &&
{
if(this->type_ != value_t::Float)
{
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
}
return std::move(this->floating_);
}
TOML11_MARK_AS_DEPRECATED("use toml::value::is_floating() instead.")
floating const& as_float() const&
{
if(this->type_ != value_t::Float)
{
detail::throw_bad_cast<value_t::Float>(this->type_, *this);
}
return this->floating_;
}
// ------------------------------------------------------------------------
std::string comment() const
{
@@ -744,16 +1069,6 @@ void change_region(value& v, Region&& reg)
return;
}
template<value_t Expected>
[[noreturn]] inline void throw_bad_cast(value_t actual, const ::toml::value& v)
{
throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", Expected), {
{std::addressof(get_region(v)),
concat_to_string("the actual type is ", actual)}
}));
}
template<value_t T>
struct switch_cast;
template<>
@@ -773,9 +1088,9 @@ struct switch_cast<value_t::Integer>
template<>
struct switch_cast<value_t::Float>
{
static ::toml::floating& invoke(value& v) {return v.as_float();}
static ::toml::floating const& invoke(value const& v) {return v.as_float();}
static ::toml::floating&& invoke(value&& v) {return std::move(v).as_float();}
static ::toml::floating& invoke(value& v) {return v.as_floating();}
static ::toml::floating const& invoke(value const& v) {return v.as_floating();}
static ::toml::floating&& invoke(value&& v) {return std::move(v).as_floating();}
};
template<>
struct switch_cast<value_t::String>
@@ -856,6 +1171,9 @@ typename detail::toml_default_type<T>::type&& value::cast() &&
return detail::switch_cast<T>::invoke(std::move(*this));
}
bool operator==(const toml::value& lhs, const toml::value& rhs);
bool operator< (const toml::value& lhs, const toml::value& rhs);
inline bool operator==(const toml::value& lhs, const toml::value& rhs)
{
if(lhs.type() != rhs.type()){return false;}
@@ -871,7 +1189,7 @@ inline bool operator==(const toml::value& lhs, const toml::value& rhs)
}
case value_t::Float :
{
return lhs.as_float() == rhs.as_float();
return lhs.as_floating() == rhs.as_floating();
}
case value_t::String :
{
@@ -921,7 +1239,7 @@ inline bool operator<(const toml::value& lhs, const toml::value& rhs)
}
case value_t::Float :
{
return lhs.as_float() < rhs.as_float();
return lhs.as_floating() < rhs.as_floating();
}
case value_t::String :
{
@@ -949,7 +1267,14 @@ inline bool operator<(const toml::value& lhs, const toml::value& rhs)
}
case value_t::Table :
{
return lhs.as_table() < rhs.as_table();
// since unordered_map does not have `operator<` ...
std::vector<std::pair<toml::key, toml::value>>
L(lhs.as_table().begin(), lhs.as_table().end()),
R(rhs.as_table().begin(), rhs.as_table().end());
std::sort(L.begin(), L.end());
std::sort(R.begin(), R.end());
return std::lexicographical_compare(
L.begin(), L.end(), R.begin(), R.end());
}
case value_t::Empty : {return false;}
case value_t::Unknown : {return false;}
@@ -1018,7 +1343,7 @@ visit(Visitor&& visitor, const toml::value& v)
{
case value_t::Boolean : {return visitor(v.as_boolean ());}
case value_t::Integer : {return visitor(v.as_integer ());}
case value_t::Float : {return visitor(v.as_float ());}
case value_t::Float : {return visitor(v.as_floating ());}
case value_t::String : {return visitor(v.as_string ());}
case value_t::OffsetDatetime: {return visitor(v.as_offset_datetime());}
case value_t::LocalDatetime : {return visitor(v.as_local_datetime ());}
@@ -1042,7 +1367,7 @@ visit(Visitor&& visitor, toml::value& v)
{
case value_t::Boolean : {return visitor(v.as_boolean ());}
case value_t::Integer : {return visitor(v.as_integer ());}
case value_t::Float : {return visitor(v.as_float ());}
case value_t::Float : {return visitor(v.as_floating ());}
case value_t::String : {return visitor(v.as_string ());}
case value_t::OffsetDatetime: {return visitor(v.as_offset_datetime());}
case value_t::LocalDatetime : {return visitor(v.as_local_datetime ());}
@@ -1066,7 +1391,7 @@ visit(Visitor&& visitor, toml::value&& v)
{
case value_t::Boolean : {return visitor(std::move(v.as_boolean ()));}
case value_t::Integer : {return visitor(std::move(v.as_integer ()));}
case value_t::Float : {return visitor(std::move(v.as_float ()));}
case value_t::Float : {return visitor(std::move(v.as_floating ()));}
case value_t::String : {return visitor(std::move(v.as_string ()));}
case value_t::OffsetDatetime: {return visitor(std::move(v.as_offset_datetime()));}
case value_t::LocalDatetime : {return visitor(std::move(v.as_local_datetime ()));}