Compare commits

...

42 Commits

Author SHA1 Message Date
ToruNiina
bfe5e50acf test: add missing include files 2020-02-07 21:00:11 +09:00
ToruNiina
05077dee0c test: add test_visit 2020-02-07 15:58:15 +09:00
ToruNiina
b9f1726e26 feat: add multi-argument toml::visit(visitor, ...) 2020-02-07 15:57:34 +09:00
ToruNiina
c583e38ebf fix: include visit.hpp from serializer 2020-02-07 15:57:09 +09:00
ToruNiina
388e9db32b refactor: move visit() from value.hpp to visit.hpp 2020-01-31 22:48:37 +09:00
ToruNiina
aa8d574dfe chore: update minor version 2020-01-24 22:08:12 +09:00
ToruNiina
49fdb61731 refactor: add explicit to ctors of internal types 2020-01-24 15:58:24 +09:00
ToruNiina
b2bb21a473 doc: update year of copyright notice 2020-01-23 22:18:04 +09:00
ToruNiina
0c58549fc6 Merge branch 'master' of github.com:ToruNiina/toml11 2020-01-22 12:20:34 +09:00
ToruNiina
b7b5e847d3 ci: test with C++14, not only 11/17 2020-01-22 12:19:53 +09:00
ToruNiina
22d630fec1 feat: replace detail::stuff by std if possible 2020-01-20 12:18:05 +09:00
ToruNiina
f7bf341452 fix: add missing noexcept specifier 2020-01-19 21:06:10 +09:00
ToruNiina
0934d90f90 refactor: move ctors that are only used internally 2020-01-19 18:30:27 +09:00
ToruNiina
f2c8d0e279 refactor: add missing explicit to toml::exception 2020-01-19 17:51:24 +09:00
ToruNiina
8c7d83d985 Merge branch 'add-value-member-methods' 2020-01-17 20:30:26 +09:00
ToruNiina
5ce44adbdc doc: add description about toml::value memfuns 2020-01-17 20:26:36 +09:00
ToruNiina
5c5b1320d0 test: add test for map/vector methods 2020-01-16 20:58:36 +09:00
ToruNiina
8b737dc21f feat: add member methods to toml::value 2020-01-16 20:58:10 +09:00
ToruNiina
ee654b6c3f chore: add -Werror when building test codes 2020-01-13 11:31:03 +09:00
ToruNiina
c59782d180 fix: remove useless conversions in the test codes 2020-01-13 11:29:17 +09:00
ToruNiina
9bef715ccd fix: use u32 as a result of binary operation 2020-01-13 11:26:53 +09:00
ToruNiina
d2b1cf5123 refactor: just use a constructor
to remove conversions
2020-01-13 11:26:29 +09:00
ToruNiina
9f92916d1d fix: suppress -Wuseless-conversion
`{integer} + 1` will automatically be an int, so static_cast<int>(a+1)
will be useless conversion.
2020-01-13 11:24:48 +09:00
ToruNiina
666e4cf9dc fix: suppress sign-conversion warnings 2020-01-13 00:46:21 +09:00
ToruNiina
cafee29c64 test: add some combinations of types in toml::find 2020-01-13 00:27:39 +09:00
ToruNiina
a7a2272b29 chore: turn more diagnostic flags on 2020-01-13 00:16:33 +09:00
ToruNiina
dc0bca2bb6 fix: update patch version ... 2020-01-12 23:18:03 +09:00
ToruNiina
490abe04fd refactor: remove redundant template argument 2020-01-12 23:07:17 +09:00
ToruNiina
81ed4c0e9d Merge branch 'master' of github.com:ToruNiina/toml11 2020-01-10 21:17:17 +09:00
ToruNiina
1b07baf184 doc: add toml::get specialization using ctor 2020-01-10 20:46:54 +09:00
ToruNiina
9073d52159 test: check get<foo> works with constructor 2020-01-10 20:39:56 +09:00
ToruNiina
55260654bf feat: get user-defined value by constructor
If a user-defined constructor has constructor(const toml::value&),
then it should be convertible in `toml::get` and `toml::find`.
2020-01-10 20:38:52 +09:00
ToruNiina
aa6271af75 doc: update README 2020-01-09 01:40:05 +09:00
ToruNiina
c54a03f189 Merge branch 'master' into find-idx 2020-01-09 00:27:51 +09:00
ToruNiina
c153c0e8c3 ci: test with sanitizers 2020-01-08 23:28:17 +09:00
ToruNiina
1f90af8e67 ci: refactor list of env vars 2020-01-08 23:17:38 +09:00
ToruNiina
a0c5192b74 chore: add option to use sanitizers 2020-01-08 23:07:05 +09:00
ToruNiina
7f020f3f44 refactor: remove error prefix
that will automatically be added in format_underline
2020-01-07 22:27:13 +09:00
ToruNiina
827b433389 Merge branch 'master' into find-idx 2020-01-07 22:13:15 +09:00
ToruNiina
1148d01c70 Merge branch 'master' into find-idx 2019-10-07 11:11:08 +09:00
ToruNiina
17d78553ff test: add test cases for find(v, idx)
- check whether find(v, idx) throws
- check find(v, ks...) works with both indices and strings
2019-10-03 15:48:04 +09:00
ToruNiina
4c12dad51f feat: add find<T>(value, idx) for arrays (#79) 2019-10-03 15:27:25 +09:00
20 changed files with 1258 additions and 251 deletions

View File

@@ -5,7 +5,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: gcc compiler: gcc
env: COMPILER="g++-5" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="g++-5" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -17,7 +17,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: gcc compiler: gcc
env: COMPILER="g++-6" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="g++-6" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -29,7 +29,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: gcc compiler: gcc
env: COMPILER="g++-7" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="g++-7" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -41,7 +41,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: gcc compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="g++-8" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -65,7 +65,19 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: gcc compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=17 TOML_HEAD=OFF env: COMPILER="g++-8" CXX_STANDARD=14
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=17
addons: addons:
apt: apt:
sources: sources:
@@ -89,7 +101,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: clang compiler: clang
env: COMPILER="clang++-3.9" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="clang++-3.9" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -103,7 +115,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: clang compiler: clang
env: COMPILER="clang++-4.0" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="clang++-4.0" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -117,7 +129,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: clang compiler: clang
env: COMPILER="clang++-5.0" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="clang++-5.0" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -131,7 +143,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: clang compiler: clang
env: COMPILER="clang++-6.0" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="clang++-6.0" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -145,7 +157,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: clang compiler: clang
env: COMPILER="clang++-7" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="clang++-7" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -159,7 +171,7 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: clang compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=11 TOML_HEAD=OFF env: COMPILER="clang++-8" CXX_STANDARD=11
addons: addons:
apt: apt:
sources: sources:
@@ -187,7 +199,21 @@ matrix:
- os: linux - os: linux
language: cpp language: cpp
compiler: clang compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=17 TOML_HEAD=OFF env: COMPILER="clang++-8" CXX_STANDARD=14
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=17
addons: addons:
apt: apt:
sources: sources:
@@ -212,6 +238,34 @@ matrix:
- clang-8 - clang-8
- g++-8 - g++-8
- boost1.70 - boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_ASAN=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_UBSAN=ON
addons:
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
- sourceline: 'ppa:mhier/libboost-latest'
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- boost1.70
- os: osx - os: osx
language: cpp language: cpp
compiler: clang compiler: clang
@@ -234,11 +288,26 @@ script:
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1 tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH} export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
fi fi
- |
if [[ "${TOML_HEAD}" != "ON" ]]; then
export TOML_HEAD="OFF"
fi
- echo "TOML_HEAD = ${TOML_HEAD}"
- |
if [[ "${WITH_ASAN}" != "ON" ]]; then
export WITH_ASAN="OFF"
fi
- echo "WITH_ASAN = ${WITH_ASAN}"
- |
if [[ "${WITH_UBSAN}" != "ON" ]]; then
export WITH_UBSAN="OFF"
fi
- echo "WITH_UBSAN = ${WITH_UBSAN}"
- cmake --version - cmake --version
- mkdir build - mkdir build
- cd build - cd build
- git clone https://github.com/toml-lang/toml.git - git clone https://github.com/toml-lang/toml.git
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} .. - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} -Dtoml11_TEST_WITH_ASAN=${WITH_ASAN} -Dtoml11_TEST_WITH_UBSAN=${WITH_UBSAN} ..
- make - make
- ctest --output-on-failure - ctest --output-on-failure

View File

@@ -4,13 +4,15 @@ enable_testing()
project(toml11) project(toml11)
set(toml11_VERSION_MAYOR 3) set(toml11_VERSION_MAYOR 3)
set(toml11_VERSION_MINOR 2) set(toml11_VERSION_MINOR 3)
set(toml11_VERSION_PATCH 0) set(toml11_VERSION_PATCH 0)
set(toml11_VERSION set(toml11_VERSION
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}" "${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
) )
option(toml11_BUILD_TEST "Build toml tests" ON) option(toml11_BUILD_TEST "Build toml tests" ON)
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
if("${CMAKE_VERSION}" VERSION_GREATER 3.1) if("${CMAKE_VERSION}" VERSION_GREATER 3.1)

View File

@@ -274,10 +274,44 @@ const auto color = toml::find<std::string>(data, "fruit", "physical", "color");
const auto shape = toml::find<std::string>(data, "fruit", "physical", "shape"); const auto shape = toml::find<std::string>(data, "fruit", "physical", "shape");
``` ```
### Finding a value in an array
You can find n-th value in an array by `toml::find`.
```toml
values = ["foo", "bar", "baz"]
```
``` cpp
const auto data = toml::parse("sample.toml");
const auto values = toml::find(data, "values");
const auto bar = toml::find<std::string>(values, 1);
```
`toml::find` can also search array recursively.
```cpp
const auto data = toml::parse("fruit.toml");
const auto bar = toml::find<std::string>(data, "values", 1);
```
Before calling `toml::find`, you can check if a value corresponding to a key
exists. You can use both `bool toml::value::contains(const key&) const` and
`std::size_t toml::value::count(const key&) const`. Those behaves like the
`std::map::contains` and `std::map::count`.
```cpp
const auto data = toml::parse("fruit.toml");
if(data.contains("fruit") && data.at("fruit").count("physical") != 0)
{
// ...
}
```
### In case of error ### In case of error
If the value does not exist, `toml::find` throws an error with the location of If the value does not exist, `toml::find` throws `std::out_of_range` with the
the table. location of the table.
```console ```console
terminate called after throwing an instance of 'std::out_of_range' terminate called after throwing an instance of 'std::out_of_range'
@@ -287,11 +321,6 @@ terminate called after throwing an instance of 'std::out_of_range'
| ~~~~~ in this table | ~~~~~ in this table
``` ```
**Note**: It is recommended to find a table as `toml::value` because it has much information
compared to `toml::table`, which is an alias of
`std::unordered_map<std::string, toml::value>`. Since `toml::table` does not have
any information about toml file, such as where the table was defined in the file.
---- ----
If the specified type differs from the actual value contained, it throws If the specified type differs from the actual value contained, it throws
@@ -869,14 +898,25 @@ toml::value v(toml::local_time(std::chrono::hours(10)));
``` ```
You can construct an array object not only from `initializer_list`, but also You can construct an array object not only from `initializer_list`, but also
from STL containers. from STL containers. In that case, the element type must be convertible to
`toml::value`.
```cpp ```cpp
std::vector<int> vec{1,2,3,4,5}; std::vector<int> vec{1,2,3,4,5};
toml::value v = vec; toml::value v(vec);
``` ```
All the elements of `initializer_list` should be convertible into `toml::value`. When you construct an array value, all the elements of `initializer_list`
must be convertible into `toml::value`.
If a `toml::value` has an array, you can `push_back` an element in it.
```cpp
toml::value v{1,2,3,4,5};
v.push_back(6);
```
`emplace_back` also works.
## Preserving comments ## Preserving comments
@@ -1093,7 +1133,7 @@ const auto data = toml::parse("example.toml");
const foo f = toml::find<ext::foo>(data, "foo"); const foo f = toml::find<ext::foo>(data, "foo");
``` ```
There are 2 ways to use `toml::get` with the types that you defined. There are 3 ways to use `toml::get` with the types that you defined.
The first one is to implement `from_toml(const toml::value&)` member function. The first one is to implement `from_toml(const toml::value&)` member function.
@@ -1120,7 +1160,31 @@ struct foo
In this way, because `toml::get` first constructs `foo` without arguments, In this way, because `toml::get` first constructs `foo` without arguments,
the type should be default-constructible. the type should be default-constructible.
The second is to implement specialization of `toml::from` for your type. The second is to implement `constructor(const toml::value&)`.
```cpp
namespace ext
{
struct foo
{
explicit foo(const toml::value& v)
: a(toml::find<int>(v, "a")), b(toml::find<double>(v, "b")),
c(toml::find<std::string>(v, "c"))
{}
int a;
double b;
std::string c;
};
} // ext
```
Note that implicit default constructor declaration will be suppressed
when a constructor is defined. If you want to use the struct (here, `foo`)
in a container (e.g. `std::vector<foo>`), you may need to define default
constructor explicitly.
The third is to implement specialization of `toml::from` for your type.
```cpp ```cpp
namespace ext namespace ext
@@ -1724,6 +1788,6 @@ I appreciate the help of the contributors who introduced the great feature to th
This product is licensed under the terms of the [MIT License](LICENSE). This product is licensed under the terms of the [MIT License](LICENSE).
- Copyright (c) 2017-2019 Toru Niina - Copyright (c) 2017-2020 Toru Niina
All rights reserved. All rights reserved.

View File

@@ -34,11 +34,21 @@ set(TEST_NAMES
test_error_detection test_error_detection
test_format_error test_format_error
test_extended_conversions test_extended_conversions
test_visit
) )
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL) CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA) CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA)
CHECK_CXX_COMPILER_FLAG("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC) 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("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
CHECK_CXX_COMPILER_FLAG("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
if(COMPILER_SUPPORTS_WALL) if(COMPILER_SUPPORTS_WALL)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
@@ -49,6 +59,30 @@ endif()
if(COMPILER_SUPPORTS_WPEDANTIC) if(COMPILER_SUPPORTS_WPEDANTIC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
endif() endif()
if(COMPILER_SUPPORTS_WERROR)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
if(COMPILER_SUPPORTS_WSIGN_CONVERSION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
endif()
if(COMPILER_SUPPORTS_WCONVERSION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
endif()
if(COMPILER_SUPPORTS_WDUPLICATED_COND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-cond")
endif()
if(COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-branches")
endif()
if(COMPILER_SUPPORTS_WLOGICAL_OP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wlogical-op")
endif()
if(COMPILER_SUPPORTS_WUSELESS_CAST)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wuseless-cast")
endif()
if(COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
endif()
option(TOML11_USE_UNRELEASED_TOML_FEATURES option(TOML11_USE_UNRELEASED_TOML_FEATURES
"use features in toml-lang/toml master while testing" OFF) "use features in toml-lang/toml master while testing" OFF)
@@ -104,6 +138,19 @@ foreach(TEST_NAME ${TEST_NAMES})
add_executable(${TEST_NAME} ${TEST_NAME}.cpp) add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11) target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS}) target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(toml11_TEST_WITH_ASAN)
set_target_properties(${TEST_NAME} PROPERTIES
COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer"
LINK_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
elseif(toml11_TEST_WITH_UBSAN)
set_target_properties(${TEST_NAME} PROPERTIES
COMPILE_FLAGS "-fsanitize=undefined"
LINK_FLAGS "-fsanitize=undefined")
endif()
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
# Set the PATH to be able to find Boost DLL # Set the PATH to be able to find Boost DLL

View File

@@ -44,6 +44,18 @@ struct qux
int a; int a;
std::string b; std::string b;
}; };
struct foobar
{
foobar() = default; // later we use std::vector<foobar>, default ctor is required.
// via constructor
explicit foobar(const toml::value& v)
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
{}
int a;
std::string b;
};
} // extlib } // extlib
namespace toml namespace toml
@@ -122,6 +134,19 @@ struct qux
int a; int a;
std::string b; std::string b;
}; };
struct foobar
{
foobar() = default; // later we use std::vector<foobar>, default ctor is required.
template<typename C, template<typename ...> class M, template<typename ...> class A>
explicit foobar(const toml::basic_value<C, M, A>& v)
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
{}
int a;
std::string b;
};
} // extlib2 } // extlib2
namespace toml namespace toml
@@ -284,6 +309,27 @@ BOOST_AUTO_TEST_CASE(test_conversion_one_way)
} }
} }
BOOST_AUTO_TEST_CASE(test_conversion_via_constructor)
{
{
const toml::value v{{"a", 42}, {"b", "foobar"}};
const auto foobar = toml::get<extlib::foobar>(v);
BOOST_TEST(foobar.a == 42);
BOOST_TEST(foobar.b == "foobar");
}
{
const toml::basic_value<toml::discard_comments, std::map> v{
{"a", 42}, {"b", "foobar"}
};
const auto foobar = toml::get<extlib2::foobar>(v);
BOOST_TEST(foobar.a == 42);
BOOST_TEST(foobar.b == "foobar");
}
}
BOOST_AUTO_TEST_CASE(test_recursive_conversion) BOOST_AUTO_TEST_CASE(test_recursive_conversion)
{ {
{ {
@@ -384,5 +430,63 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion)
BOOST_TEST(bars.at(2).b == "quux"); BOOST_TEST(bars.at(2).b == "quux");
BOOST_TEST(bars.at(3).b == "foobar"); BOOST_TEST(bars.at(3).b == "foobar");
} }
// via constructor
{
const toml::value v{
toml::table{{"a", 42}, {"b", "baz"}},
toml::table{{"a", 43}, {"b", "qux"}},
toml::table{{"a", 44}, {"b", "quux"}},
toml::table{{"a", 45}, {"b", "foobar"}}
};
{
const auto foobars = toml::get<std::vector<extlib::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
{
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque>
v{
toml::table{{"a", 42}, {"b", "baz"}},
toml::table{{"a", 43}, {"b", "qux"}},
toml::table{{"a", 44}, {"b", "quux"}},
toml::table{{"a", 45}, {"b", "foobar"}}
};
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
} }

View File

@@ -101,6 +101,78 @@ BOOST_AUTO_TEST_CASE(test_find_throws)
} }
} }
BOOST_AUTO_TEST_CASE(test_find_array_throws)
{
// -----------------------------------------------------------------------
// const-reference version
{
// value is not an array
const toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
const toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not found
const toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
}
{
// the positive control.
const toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(v, 2));
}
// -----------------------------------------------------------------------
// non-const reference version
{
// value is not an array
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
}
{
// the positive control.
toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(v, 2));
}
// -----------------------------------------------------------------------
// move version
{
// value is not an array
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(std::move(v), 6), std::out_of_range);
}
{
// the positive control.
toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(std::move(v), 2));
}
}
BOOST_AUTO_TEST_CASE(test_find_recursive) BOOST_AUTO_TEST_CASE(test_find_recursive)
{ {
// recursively search tables // recursively search tables
@@ -126,8 +198,76 @@ BOOST_AUTO_TEST_CASE(test_find_recursive)
num2 = 42; num2 = 42;
BOOST_TEST(42 == toml::find<int>(v, a, b, c, d)); BOOST_TEST(42 == toml::find<int>(v, a, b, c, d));
auto num3 = toml::find<toml::integer>(std::move(v), a, b, c, d); auto num3 = toml::find<toml::integer>(v, a, "b", c, "d");
BOOST_TEST(42 == num3); BOOST_TEST(42 == num3);
auto num4 = toml::find<toml::integer>(std::move(v), a, b, c, d);
BOOST_TEST(42 == num4);
}
// recursively search arrays
{
toml::value v{
toml::array{"array", "of", "string"},
toml::array{toml::array{1, 2, 3}, toml::array{3.14, 2.71}}
};
BOOST_TEST("array" == toml::find<std::string>(v, 0, 0));
BOOST_TEST("of" == toml::find<std::string>(v, 0, 1));
BOOST_TEST("string" == toml::find<std::string>(v, 0, 2));
BOOST_TEST(1 == toml::find<int>(v, 1, 0, 0));
BOOST_TEST(2 == toml::find<int>(v, 1, 0, 1));
BOOST_TEST(3 == toml::find<int>(v, 1, 0, 2));
BOOST_TEST(3.14 == toml::find<double>(v, 1, 1, 0));
BOOST_TEST(2.71 == toml::find<double>(v, 1, 1, 1));
// reference that can be used to modify the content
auto& num = toml::find<toml::integer>(v, 1, 0, 2);
num = 42;
BOOST_TEST( 1 == toml::find<int>(v, 1, 0, 0));
BOOST_TEST( 2 == toml::find<int>(v, 1, 0, 1));
BOOST_TEST(42 == toml::find<int>(v, 1, 0, 2));
// move value
auto num2 = toml::find<toml::integer>(std::move(v), 1, 0, 2);
BOOST_TEST(42 == num2);
}
// 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}}
}}
}};
BOOST_TEST(1 == toml::find<int>(v, "array", 0, 0));
BOOST_TEST(2 == toml::find<int>(v, "array", 0, 1));
BOOST_TEST(3 == toml::find<int>(v, "array", 0, 2));
BOOST_TEST("bar" == toml::find<std::string>(v, "array", 1, 0, "foo"));
BOOST_TEST("qux" == toml::find<std::string>(v, "array", 1, 0, "baz"));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, "pi"));
BOOST_TEST(2.71 == toml::find<double>(v, "array", 1, 1, "e"));
const std::string ar("array");
const auto ar_c = "array";
const std::string pi("pi");
const auto pi_c = "pi";
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, "pi"));
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi_c));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, "pi"));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi_c));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi_c));
} }
} }
@@ -309,10 +449,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_floating_type, value_type, test_value_ty
{ {
{ {
value_type v{{"key", 3.14}}; value_type v{{"key", 3.14}};
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(v, "key")); const double ref(3.14);
BOOST_TEST(static_cast<double >(3.14) == toml::find<double >(v, "key")); BOOST_TEST(static_cast<float >(ref) == toml::find<float >(v, "key"));
BOOST_TEST(static_cast<long double>(3.14) == toml::find<long double>(v, "key")); BOOST_TEST( ref == toml::find<double >(v, "key"));
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(std::move(v), "key")); BOOST_TEST(static_cast<long double>(ref) == toml::find<long double>(v, "key"));
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(std::move(v), "key"));
} }
} }
@@ -373,14 +514,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array, value_type, test_value_types
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3)); BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key"); std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key");
BOOST_TEST(static_cast<int>(42) == ary.at(0)); BOOST_TEST(42 == ary.at(0));
BOOST_TEST(static_cast<int>(54) == ary.at(1)); BOOST_TEST(54 == ary.at(1));
BOOST_TEST(static_cast<int>(69) == ary.at(2)); BOOST_TEST(69 == ary.at(2));
BOOST_TEST(static_cast<int>(72) == ary.at(3)); BOOST_TEST(72 == ary.at(3));
std::tuple<int, short, unsigned, long> tpl = std::tuple<int, short, unsigned, long> tpl =
toml::find<std::tuple<int, short, unsigned, long>>(v, "key"); toml::find<std::tuple<int, short, unsigned, long>>(v, "key");
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl)); BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl)); BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl)); BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl)); BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
@@ -420,14 +561,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_move_toml_array, value_type, test_value_
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3)); BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::find<std::array<int, 4>>(std::move(v4), "key"); std::array<int, 4> ary = toml::find<std::array<int, 4>>(std::move(v4), "key");
BOOST_TEST(static_cast<int>(42) == ary.at(0)); BOOST_TEST(42 == ary.at(0));
BOOST_TEST(static_cast<int>(54) == ary.at(1)); BOOST_TEST(54 == ary.at(1));
BOOST_TEST(static_cast<int>(69) == ary.at(2)); BOOST_TEST(69 == ary.at(2));
BOOST_TEST(static_cast<int>(72) == ary.at(3)); BOOST_TEST(72 == ary.at(3));
std::tuple<int, short, unsigned, long> tpl = std::tuple<int, short, unsigned, long> tpl =
toml::find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key"); toml::find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key");
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl)); BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl)); BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl)); BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl)); BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));

View File

@@ -375,7 +375,8 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
toml::value v1{{"key", 42}}; toml::value v1{{"key", 42}};
toml::value v2{{"key", 3.14}}; toml::value v2{{"key", 3.14}};
BOOST_TEST(2.71f == toml::find_or(v1, "key", 2.71f)); BOOST_TEST(2.71f == toml::find_or(v1, "key", 2.71f));
BOOST_TEST(static_cast<float>(double(3.14)) == toml::find_or(v2, "key", 2.71f)); const double ref(3.14);
BOOST_TEST(static_cast<float>(ref) == toml::find_or(v2, "key", 2.71f));
} }
{ {
toml::value v1{{"key", 42}}; toml::value v1{{"key", 42}};
@@ -383,7 +384,8 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
const auto moved1 = toml::find_or(std::move(v1), "key", 2.71f); const auto moved1 = toml::find_or(std::move(v1), "key", 2.71f);
const auto moved2 = toml::find_or(std::move(v2), "key", 2.71f); const auto moved2 = toml::find_or(std::move(v2), "key", 2.71f);
BOOST_TEST(2.71f == moved1); BOOST_TEST(2.71f == moved1);
BOOST_TEST(static_cast<float>(double(3.14)) == moved2); const double ref(3.14);
BOOST_TEST(static_cast<float>(ref) == moved2);
} }
} }

View File

@@ -195,11 +195,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_floating_type, value_type, test_value_typ
{ {
{ {
value_type v(3.14); value_type v(3.14);
BOOST_TEST(static_cast<float >(3.14) == toml::get<float >(v)); const double ref(3.14);
BOOST_TEST(static_cast<double >(3.14) == toml::get<double >(v)); BOOST_TEST(static_cast<float >(ref) == toml::get<float >(v));
BOOST_TEST(static_cast<long double>(3.14) == toml::get<long double>(v)); BOOST_TEST( ref == toml::get<double >(v));
BOOST_TEST(static_cast<long double>(ref) == toml::get<long double>(v));
BOOST_TEST(3.14f == toml::get<float>(std::move(v))); BOOST_TEST(static_cast<float >(ref) == toml::get<float>(std::move(v)));
} }
} }
@@ -262,14 +262,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3)); BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v); std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
BOOST_TEST(static_cast<int>(42) == ary.at(0)); BOOST_TEST(42 == ary.at(0));
BOOST_TEST(static_cast<int>(54) == ary.at(1)); BOOST_TEST(54 == ary.at(1));
BOOST_TEST(static_cast<int>(69) == ary.at(2)); BOOST_TEST(69 == ary.at(2));
BOOST_TEST(static_cast<int>(72) == ary.at(3)); BOOST_TEST(72 == ary.at(3));
std::tuple<int, short, unsigned, long> tpl = std::tuple<int, short, unsigned, long> tpl =
toml::get<std::tuple<int, short, unsigned, long>>(v); toml::get<std::tuple<int, short, unsigned, long>>(v);
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl)); BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl)); BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl)); BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl)); BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
@@ -308,16 +308,16 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
{ {
value_type v{42, 54, 69, 72}; value_type v{42, 54, 69, 72};
std::array<int, 4> ary = toml::get<std::array<int, 4>>(std::move(v)); std::array<int, 4> ary = toml::get<std::array<int, 4>>(std::move(v));
BOOST_TEST(static_cast<int>(42) == ary.at(0)); BOOST_TEST(42 == ary.at(0));
BOOST_TEST(static_cast<int>(54) == ary.at(1)); BOOST_TEST(54 == ary.at(1));
BOOST_TEST(static_cast<int>(69) == ary.at(2)); BOOST_TEST(69 == ary.at(2));
BOOST_TEST(static_cast<int>(72) == ary.at(3)); BOOST_TEST(72 == ary.at(3));
} }
{ {
value_type v{42, 54, 69, 72}; value_type v{42, 54, 69, 72};
std::tuple<int, short, unsigned, long> tpl = std::tuple<int, short, unsigned, long> tpl =
toml::get<std::tuple<int, short, unsigned, long>>(std::move(v)); toml::get<std::tuple<int, short, unsigned, long>>(std::move(v));
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl)); BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl)); BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl)); BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl)); BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));

View File

@@ -966,3 +966,54 @@ BOOST_AUTO_TEST_CASE(test_value_bracket)
BOOST_CHECK_THROW(v1["foo"], toml::type_error); BOOST_CHECK_THROW(v1["foo"], toml::type_error);
} }
} }
BOOST_AUTO_TEST_CASE(test_value_map_methods)
{
{
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
BOOST_TEST(v1.count("foo") == 1u);
BOOST_TEST(v1.count("bar") == 1u);
BOOST_TEST(v1.count("baz") == 1u);
BOOST_TEST(v1.count("qux") == 0u);
BOOST_TEST( v1.contains("foo"));
BOOST_TEST( v1.contains("bar"));
BOOST_TEST( v1.contains("baz"));
BOOST_TEST(!v1.contains("qux"));
BOOST_TEST(v1.size() == 3);
v1["qux"] = 54;
BOOST_TEST(v1.count("qux") == 1u);
BOOST_TEST(v1.contains("qux"));
BOOST_TEST(v1.size() == 4);
}
{
toml::value v1(42);
BOOST_CHECK_THROW(v1.size() , toml::type_error);
BOOST_CHECK_THROW(v1.count("k") , toml::type_error);
BOOST_CHECK_THROW(v1.contains("k"), toml::type_error);
}
}
BOOST_AUTO_TEST_CASE(test_value_vector_methods)
{
{
toml::value v1{1, 2, 3, 4, 5};
BOOST_TEST(v1.size() == 5);
v1.push_back(6);
BOOST_TEST(v1.size() == 6);
v1.emplace_back(6);
BOOST_TEST(v1.size() == 7);
}
{
toml::value v1(42);
BOOST_CHECK_THROW(v1.size(), toml::type_error);
BOOST_CHECK_THROW(v1.push_back(1), toml::type_error);
BOOST_CHECK_THROW(v1.emplace_back(1), toml::type_error);
}
}

172
tests/test_visit.cpp Normal file
View File

@@ -0,0 +1,172 @@
#define BOOST_TEST_MODULE "test_visit"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <deque>
using test_value_types = std::tuple<
toml::value,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
template<typename Value>
struct visitor1
{
std::string operator()(const toml::boolean&) const {return "boolean";}
std::string operator()(const toml::integer&) const {return "integer";}
std::string operator()(const toml::floating&) const {return "floating";}
std::string operator()(const toml::string&) const {return "string";}
std::string operator()(const toml::local_time&) const {return "local_time";}
std::string operator()(const toml::local_date&) const {return "local_date";}
std::string operator()(const toml::local_datetime&) const {return "local_datetime";}
std::string operator()(const toml::offset_datetime&) const {return "offset_datetime";}
std::string operator()(const typename Value::array_type&) const {return "array";}
std::string operator()(const typename Value::table_type&) const {return "table";}
};
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_one, value_type, test_value_types)
{
{
const value_type v(true);
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "boolean");
}
{
const value_type v(42);
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "integer");
}
{
const value_type v(3.14);
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "floating");
}
{
const value_type v("foo");
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "string");
}
{
const value_type v(toml::local_date(2018, toml::month_t::Apr, 22));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_date");
}
{
const value_type v(toml::local_time(12, 34, 56));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_time");
}
{
const value_type v(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56)));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_datetime");
}
{
const value_type v(toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56),
toml::time_offset(9, 0)));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "offset_datetime");
}
{
const value_type v{1,2,3,4,5};
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "array");
}
{
const value_type v{
{"foo", 42}, {"bar", "baz"}
};
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "table");
}
}
template<typename Value>
struct visitor2
{
template<typename T1, typename T2>
std::string operator()(const T1& v1, const T2& v2) const
{
visitor1<Value> vis;
return vis(v1) + "+" + vis(v2);
}
};
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_two, value_type, test_value_types)
{
std::vector<value_type> vs;
vs.push_back(value_type(true));
vs.push_back(value_type(42));
vs.push_back(value_type(3.14));
vs.push_back(value_type("foo"));
vs.push_back(value_type(toml::local_date(2018, toml::month_t::Apr, 22)));
vs.push_back(value_type(toml::local_time(12, 34, 56)));
vs.push_back(value_type(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56))));
vs.push_back(value_type(toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56),
toml::time_offset(9, 0))));
vs.push_back(value_type{1,2,3,4,5});
vs.push_back(value_type{{"foo", 42}, {"bar", "baz"}});
for(const auto& v1 : vs)
{
const auto t1 = toml::visit(visitor1<value_type>{}, v1);
for(const auto& v2 : vs)
{
const auto t2 = toml::visit(visitor1<value_type>{}, v2);
BOOST_TEST(toml::visit(visitor2<value_type>{}, v1, v2) ==
t1 + "+" + t2);
}
}
}
template<typename Value>
struct visitor3
{
template<typename T1, typename T2, typename T3>
std::string operator()(const T1& v1, const T2& v2, const T3& v3) const
{
visitor1<Value> vis;
return vis(v1) + "+" + vis(v2) + "+" + vis(v3);
}
};
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_three, value_type, test_value_types)
{
std::vector<value_type> vs;
vs.push_back(value_type(true));
vs.push_back(value_type(42));
vs.push_back(value_type(3.14));
vs.push_back(value_type("foo"));
vs.push_back(value_type(toml::local_date(2018, toml::month_t::Apr, 22)));
vs.push_back(value_type(toml::local_time(12, 34, 56)));
vs.push_back(value_type(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56))));
vs.push_back(value_type(toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56),
toml::time_offset(9, 0))));
vs.push_back(value_type{1,2,3,4,5});
vs.push_back(value_type{{"foo", 42}, {"bar", "baz"}});
for(const auto& v1 : vs)
{
const auto t1 = toml::visit(visitor1<value_type>{}, v1);
for(const auto& v2 : vs)
{
const auto t2 = toml::visit(visitor1<value_type>{}, v2);
for(const auto& v3 : vs)
{
const auto t3 = toml::visit(visitor1<value_type>{}, v3);
BOOST_TEST(toml::visit(visitor3<value_type>{}, v1, v2, v3) ==
t1 + "+" + t2 + "+" + t3);
}
}
}
}

View File

@@ -173,8 +173,8 @@ std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const local_date& date) operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
{ {
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-'; os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month + 1) << '-'; os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ); os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ) ;
return os; return os;
} }

View File

@@ -12,7 +12,7 @@ namespace toml
struct exception : public std::exception struct exception : public std::exception
{ {
public: public:
exception(const source_location& loc): loc_(loc) {} explicit exception(const source_location& loc): loc_(loc) {}
virtual ~exception() noexcept override = default; virtual ~exception() noexcept override = default;
virtual const char* what() const noexcept override {return "";} virtual const char* what() const noexcept override {return "";}
virtual source_location const& location() const noexcept {return loc_;} virtual source_location const& location() const noexcept {return loc_;}

View File

@@ -259,6 +259,15 @@ template<typename T, typename C,
std::size_t S = sizeof(::toml::from<T>)> std::size_t S = sizeof(::toml::from<T>)>
T get(const basic_value<C, M, V>&); T get(const basic_value<C, M, V>&);
// T(const toml::value&) and T is not toml::basic_value
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<detail::conjunction<
detail::negation<detail::is_basic_value<T>>,
std::is_constructible<T, const basic_value<C, M, V>&>
>::value, T>
get(const basic_value<C, M, V>&);
// ============================================================================ // ============================================================================
// array-like types; most likely STL container, like std::vector, etc. // array-like types; most likely STL container, like std::vector, etc.
@@ -417,6 +426,17 @@ T get(const basic_value<C, M, V>& v)
return ::toml::from<T>::from_toml(v); return ::toml::from<T>::from_toml(v);
} }
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<detail::conjunction<
detail::negation<detail::is_basic_value<T>>,
std::is_constructible<T, const basic_value<C, M, V>&>
>::value, T>
get(const basic_value<C, M, V>& v)
{
return T(v);
}
// ============================================================================ // ============================================================================
// find // find
@@ -465,6 +485,52 @@ basic_value<C, M, V> find(basic_value<C, M, V>&& v, const key& ky)
return basic_value<C, M, V>(std::move(tab.at(ky))); return basic_value<C, M, V>(std::move(tab.at(ky)));
} }
// ----------------------------------------------------------------------------
// find(value, idx)
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V> const&
find(const basic_value<C, M, V>& v, const std::size_t idx)
{
const auto& ary = v.as_array();
if(ary.size() <= idx)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"index ", idx, " is out of range"), {
{std::addressof(detail::get_region(v)), "in this array"}
}));
}
return ary.at(idx);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V>& find(basic_value<C, M, V>& v, const std::size_t idx)
{
auto& ary = v.as_array();
if(ary.size() <= idx)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"index ", idx, " is out of range"), {
{std::addressof(detail::get_region(v)), "in this array"}
}));
}
return ary.at(idx);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V> find(basic_value<C, M, V>&& v, const std::size_t idx)
{
auto& ary = v.as_array();
if(ary.size() <= idx)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"index ", idx, " is out of range"), {
{std::addressof(detail::get_region(v)), "in this array"}
}));
}
return basic_value<C, M, V>(std::move(ary.at(idx)));
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// find<T>(value, key); // find<T>(value, key);
@@ -516,57 +582,152 @@ find(basic_value<C, M, V>&& v, const key& ky)
return ::toml::get<T>(std::move(tab.at(ky))); return ::toml::get<T>(std::move(tab.at(ky)));
} }
// ----------------------------------------------------------------------------
// find<T>(value, idx)
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
find(const basic_value<C, M, V>& v, const std::size_t idx)
{
const auto& ary = v.as_array();
if(ary.size() <= idx)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"index ", idx, " is out of range"), {
{std::addressof(detail::get_region(v)), "in this array"}
}));
}
return ::toml::get<T>(ary.at(idx));
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
find(basic_value<C, M, V>& v, const std::size_t idx)
{
auto& ary = v.as_array();
if(ary.size() <= idx)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"index ", idx, " is out of range"), {
{std::addressof(detail::get_region(v)), "in this array"}
}));
}
return ::toml::get<T>(ary.at(idx));
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
find(basic_value<C, M, V>&& v, const std::size_t idx)
{
typename basic_value<C, M, V>::array_type ary = std::move(v).as_array();
if(ary.size() <= idx)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"index ", idx, " is out of range"), {
{std::addressof(detail::get_region(v)), "in this array"}
}));
}
return ::toml::get<T>(std::move(ary.at(idx)));
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// toml::find(toml::value, toml::key, Ts&& ... keys) // toml::find(toml::value, toml::key, Ts&& ... keys)
namespace detail
{
// It suppresses warnings by -Wsign-conversion. Let's say we have the following
// code.
// ```cpp
// const auto x = toml::find<std::string>(data, "array", 0);
// ```
// Here, the type of literal number `0` is `int`. `int` is a signed integer.
// `toml::find` takes `std::size_t` as an index. So it causes implicit sign
// conversion and `-Wsign-conversion` warns about it. Using `0u` instead of `0`
// suppresses the warning, but it makes user code messy.
// To suppress this warning, we need to be aware of type conversion caused
// by `toml::find(v, key1, key2, ... keys)`. But the thing is that the types of
// keys can be any combination of {string-like, size_t-like}. Of course we can't
// write down all the combinations. Thus we need to use some function that
// recognize the type of argument and cast it into `std::string` or
// `std::size_t` depending on the context.
// `key_cast` does the job. It has 2 overloads. One is invoked when the
// argument type is an integer and cast the argument into `std::size_t`. The
// other is invoked when the argument type is not an integer, possibly one of
// std::string, const char[N] or const char*, and construct std::string from
// the argument.
// `toml::find(v, k1, k2, ... ks)` uses `key_cast` before passing `ks` to
// `toml::find(v, k)` to suppress -Wsign-conversion.
template<typename T>
enable_if_t<conjunction<std::is_integral<remove_cvref_t<T>>,
negation<std::is_same<remove_cvref_t<T>, bool>>>::value, std::size_t>
key_cast(T&& v) noexcept
{
return std::size_t(v);
}
template<typename T>
enable_if_t<negation<conjunction<std::is_integral<remove_cvref_t<T>>,
negation<std::is_same<remove_cvref_t<T>, bool>>>>::value, std::string>
key_cast(T&& v) noexcept
{
return std::string(std::forward<T>(v));
}
} // detail
template<typename C, template<typename C,
template<typename ...> class M, template<typename ...> class V, template<typename ...> class M, template<typename ...> class V,
typename ... Ts> typename Key1, typename Key2, typename ... Keys>
const basic_value<C, M, V>& const basic_value<C, M, V>&
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys) find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
{ {
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...); return ::toml::find(::toml::find(v, detail::key_cast(k1)),
detail::key_cast(k2), std::forward<Keys>(keys)...);
} }
template<typename C, template<typename C,
template<typename ...> class M, template<typename ...> class V, template<typename ...> class M, template<typename ...> class V,
typename ... Ts> typename Key1, typename Key2, typename ... Keys>
basic_value<C, M, V>& basic_value<C, M, V>&
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys) find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
{ {
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...); return ::toml::find(::toml::find(v, detail::key_cast(k1)),
detail::key_cast(k2), std::forward<Keys>(keys)...);
} }
template<typename C, template<typename C,
template<typename ...> class M, template<typename ...> class V, template<typename ...> class M, template<typename ...> class V,
typename ... Ts> typename Key1, typename Key2, typename ... Keys>
basic_value<C, M, V> basic_value<C, M, V>
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys) find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
{ {
return ::toml::find(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...); return ::toml::find(::toml::find(std::move(v), std::forward<Key1>(k1)),
detail::key_cast(k2), std::forward<Keys>(keys)...);
} }
template<typename T, typename C, template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V, template<typename ...> class M, template<typename ...> class V,
typename ... Ts> typename Key1, typename Key2, typename ... Keys>
decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>())) decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>()))
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys) find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
{ {
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...); return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
detail::key_cast(k2), std::forward<Keys>(keys)...);
} }
template<typename T, typename C, template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V, template<typename ...> class M, template<typename ...> class V,
typename ... Ts> typename Key1, typename Key2, typename ... Keys>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>())) decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys) find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
{ {
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...); return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
detail::key_cast(k2), std::forward<Keys>(keys)...);
} }
template<typename T, typename C, template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V, template<typename ...> class M, template<typename ...> class V,
typename ... Ts> typename Key1, typename Key2, typename ... Keys>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>())) decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys) find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
{ {
return ::toml::find<T>(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...); return ::toml::find<T>(::toml::find(std::move(v), detail::key_cast(k1)),
detail::key_cast(k2), std::forward<Keys>(keys)...);
} }
// ============================================================================ // ============================================================================

View File

@@ -256,7 +256,7 @@ std::string read_utf8_codepoint(const region<Container>& reg,
std::istringstream iss(str); std::istringstream iss(str);
iss >> std::hex >> codepoint; iss >> std::hex >> codepoint;
const auto to_char = [](const int i) noexcept -> char { const auto to_char = [](const std::uint_least32_t i) noexcept -> char {
const auto uc = static_cast<unsigned char>(i); const auto uc = static_cast<unsigned char>(i);
return *reinterpret_cast<const char*>(std::addressof(uc)); return *reinterpret_cast<const char*>(std::addressof(uc));
}; };
@@ -792,13 +792,13 @@ parse_offset_datetime(location<Container>& loc)
const auto str = ofs.unwrap().str(); const auto str = ofs.unwrap().str();
if(str.front() == '+') if(str.front() == '+')
{ {
offset.hour = static_cast<std::int8_t>(from_string<int>(str.substr(1,2), 0)); offset = time_offset(from_string<int>(str.substr(1,2), 0),
offset.minute = static_cast<std::int8_t>(from_string<int>(str.substr(4,2), 0)); from_string<int>(str.substr(4,2), 0));
} }
else else
{ {
offset.hour = -static_cast<std::int8_t>(from_string<int>(str.substr(1,2), 0)); offset = time_offset(-from_string<int>(str.substr(1,2), 0),
offset.minute = -static_cast<std::int8_t>(from_string<int>(str.substr(4,2), 0)); -from_string<int>(str.substr(4,2), 0));
} }
} }
else if(*inner_loc.iter() != 'Z' && *inner_loc.iter() != 'z') else if(*inner_loc.iter() != 'Z' && *inner_loc.iter() != 'z')

View File

@@ -4,6 +4,7 @@
#define TOML11_SERIALIZER_HPP #define TOML11_SERIALIZER_HPP
#include "value.hpp" #include "value.hpp"
#include "lexer.hpp" #include "lexer.hpp"
#include "visit.hpp"
#include <limits> #include <limits>
#include <cstdio> #include <cstdio>

View File

@@ -16,10 +16,9 @@ struct storage
{ {
using value_type = T; using value_type = T;
storage(value_type const& v): ptr(toml::make_unique<T>(v)) {} explicit storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {} explicit storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
~storage() = default; ~storage() = default;
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {} storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
storage& operator=(const storage& rhs) storage& operator=(const storage& rhs)
{ {

View File

@@ -111,6 +111,14 @@ struct has_into_toml_method
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// C++17 and/or/not // C++17 and/or/not
#if __cplusplus >= 201703L
using std::conjunction;
using std::disjunction;
using std::negation;
#else
template<typename ...> struct conjunction : std::true_type{}; template<typename ...> struct conjunction : std::true_type{};
template<typename T> struct conjunction<T> : T{}; template<typename T> struct conjunction<T> : T{};
template<typename T, typename ... Ts> template<typename T, typename ... Ts>
@@ -128,6 +136,8 @@ struct disjunction<T, Ts...> :
template<typename T> template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{}; struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
#endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// type checkers // type checkers
@@ -182,6 +192,13 @@ struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// C++14 index_sequence // C++14 index_sequence
#if __cplusplus >= 201402L
using std::index_sequence;
using std::make_index_sequence;
#else
template<std::size_t ... Ns> struct index_sequence{}; template<std::size_t ... Ns> struct index_sequence{};
template<typename IS, std::size_t N> struct push_back_index_sequence{}; template<typename IS, std::size_t N> struct push_back_index_sequence{};
@@ -205,11 +222,22 @@ struct index_sequence_maker<0>
template<std::size_t N> template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type; using make_index_sequence = typename index_sequence_maker<N-1>::type;
#endif // __cplusplus >= 2014
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// C++14 enable_if_t // C++14 enable_if_t
#if __cplusplus >= 201402L
using std::enable_if_t;
#else
template<bool B, typename T> template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type; using enable_if_t = typename std::enable_if<B, T>::type;
#endif // __cplusplus >= 2014
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// return_type_of_t // return_type_of_t

View File

@@ -20,12 +20,20 @@
namespace toml namespace toml
{ {
#if __cplusplus >= 201402L
using std::make_unique;
#else
template<typename T, typename ... Ts> template<typename T, typename ... Ts>
inline std::unique_ptr<T> make_unique(Ts&& ... args) inline std::unique_ptr<T> make_unique(Ts&& ... args)
{ {
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...)); return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
} }
#endif // __cplusplus >= 2014
namespace detail namespace detail
{ {
@@ -76,10 +84,10 @@ std::string concat_to_string(Ts&& ... args)
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...); return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
} }
template<typename T, typename U> template<typename T>
T from_string(const std::string& str, U&& opt) T from_string(const std::string& str, T opt)
{ {
T v(static_cast<T>(std::forward<U>(opt))); T v(opt);
std::istringstream iss(str); std::istringstream iss(str);
iss >> v; iss >> v;
return v; return v;

View File

@@ -529,14 +529,6 @@ class basic_value
assigner(this->boolean_, b); assigner(this->boolean_, b);
return *this; return *this;
} }
template<typename Container>
basic_value(boolean b, detail::region<Container> reg)
: type_(value_t::boolean),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->boolean_, b);
}
basic_value(boolean b, std::vector<std::string> comments) basic_value(boolean b, std::vector<std::string> comments)
: type_(value_t::boolean), : type_(value_t::boolean),
region_info_(std::make_shared<region_base>(region_base{})), region_info_(std::make_shared<region_base>(region_base{})),
@@ -557,19 +549,6 @@ class basic_value
assigner(this->integer_, static_cast<integer>(i)); assigner(this->integer_, static_cast<integer>(i));
} }
template<typename T, typename Container, typename std::enable_if<
detail::conjunction<
std::is_integral<T>,
detail::negation<std::is_same<T, boolean>>
>::value, std::nullptr_t>::type = nullptr>
basic_value(T i, detail::region<Container> reg)
: type_(value_t::integer),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->integer_, static_cast<integer>(i));
}
template<typename T, typename std::enable_if<detail::conjunction< template<typename T, typename std::enable_if<detail::conjunction<
std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value, std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
std::nullptr_t>::type = nullptr> std::nullptr_t>::type = nullptr>
@@ -604,15 +583,6 @@ class basic_value
assigner(this->floating_, static_cast<floating>(f)); assigner(this->floating_, static_cast<floating>(f));
} }
template<typename T, typename Container, typename std::enable_if<
std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
basic_value(T f, detail::region<Container> reg)
: type_(value_t::floating),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->floating_, static_cast<floating>(f));
}
template<typename T, typename std::enable_if< template<typename T, typename std::enable_if<
std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr> std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
@@ -643,14 +613,6 @@ class basic_value
{ {
assigner(this->string_, std::move(s)); assigner(this->string_, std::move(s));
} }
template<typename Container>
basic_value(toml::string s, detail::region<Container> reg)
: type_(value_t::string),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->string_, std::move(s));
}
basic_value& operator=(toml::string s) basic_value& operator=(toml::string s)
{ {
this->cleanup(); this->cleanup();
@@ -782,14 +744,6 @@ class basic_value
{ {
assigner(this->local_date_, ld); assigner(this->local_date_, ld);
} }
template<typename Container>
basic_value(const local_date& ld, detail::region<Container> reg)
: type_(value_t::local_date),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->local_date_, ld);
}
basic_value& operator=(const local_date& ld) basic_value& operator=(const local_date& ld)
{ {
this->cleanup(); this->cleanup();
@@ -814,14 +768,6 @@ class basic_value
{ {
assigner(this->local_time_, lt); assigner(this->local_time_, lt);
} }
template<typename Container>
basic_value(const local_time& lt, detail::region<Container> reg)
: type_(value_t::local_time),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->local_time_, lt);
}
basic_value(const local_time& lt, std::vector<std::string> comments) basic_value(const local_time& lt, std::vector<std::string> comments)
: type_(value_t::local_time), : type_(value_t::local_time),
region_info_(std::make_shared<region_base>(region_base{})), region_info_(std::make_shared<region_base>(region_base{})),
@@ -872,14 +818,6 @@ class basic_value
{ {
assigner(this->local_datetime_, ldt); assigner(this->local_datetime_, ldt);
} }
template<typename Container>
basic_value(const local_datetime& ldt, detail::region<Container> reg)
: type_(value_t::local_datetime),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->local_datetime_, ldt);
}
basic_value(const local_datetime& ldt, std::vector<std::string> comments) basic_value(const local_datetime& ldt, std::vector<std::string> comments)
: type_(value_t::local_datetime), : type_(value_t::local_datetime),
region_info_(std::make_shared<region_base>(region_base{})), region_info_(std::make_shared<region_base>(region_base{})),
@@ -904,14 +842,6 @@ class basic_value
{ {
assigner(this->offset_datetime_, odt); assigner(this->offset_datetime_, odt);
} }
template<typename Container>
basic_value(const offset_datetime& odt, detail::region<Container> reg)
: type_(value_t::offset_datetime),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->offset_datetime_, odt);
}
basic_value(const offset_datetime& odt, std::vector<std::string> comments) basic_value(const offset_datetime& odt, std::vector<std::string> comments)
: type_(value_t::offset_datetime), : type_(value_t::offset_datetime),
region_info_(std::make_shared<region_base>(region_base{})), region_info_(std::make_shared<region_base>(region_base{})),
@@ -958,14 +888,6 @@ class basic_value
{ {
assigner(this->array_, ary); assigner(this->array_, ary);
} }
template<typename Container>
basic_value(const array_type& ary, detail::region<Container> reg)
: type_(value_t::array),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->array_, ary);
}
basic_value(const array_type& ary, std::vector<std::string> comments) basic_value(const array_type& ary, std::vector<std::string> comments)
: type_(value_t::array), : type_(value_t::array),
region_info_(std::make_shared<region_base>(region_base{})), region_info_(std::make_shared<region_base>(region_base{})),
@@ -1079,14 +1001,6 @@ class basic_value
{ {
assigner(this->table_, tab); assigner(this->table_, tab);
} }
template<typename Container>
basic_value(const table_type& tab, detail::region<Container> reg)
: type_(value_t::table),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->table_, tab);
}
basic_value(const table_type& tab, std::vector<std::string> comments) basic_value(const table_type& tab, std::vector<std::string> comments)
: type_(value_t::table), : type_(value_t::table),
region_info_(std::make_shared<region_base>(region_base{})), region_info_(std::make_shared<region_base>(region_base{})),
@@ -1216,6 +1130,93 @@ class basic_value
} }
// for internal use ------------------------------------------------------ // for internal use ------------------------------------------------------
//
// Those constructors take detail::region that contains parse result.
template<typename Container>
basic_value(boolean b, detail::region<Container> reg)
: type_(value_t::boolean),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->boolean_, b);
}
template<typename T, typename Container, typename std::enable_if<
detail::conjunction<
std::is_integral<T>, detail::negation<std::is_same<T, boolean>>
>::value, std::nullptr_t>::type = nullptr>
basic_value(T i, detail::region<Container> reg)
: type_(value_t::integer),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->integer_, static_cast<integer>(i));
}
template<typename T, typename Container, typename std::enable_if<
std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
basic_value(T f, detail::region<Container> reg)
: type_(value_t::floating),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->floating_, static_cast<floating>(f));
}
template<typename Container>
basic_value(toml::string s, detail::region<Container> reg)
: type_(value_t::string),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->string_, std::move(s));
}
template<typename Container>
basic_value(const local_date& ld, detail::region<Container> reg)
: type_(value_t::local_date),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->local_date_, ld);
}
template<typename Container>
basic_value(const local_time& lt, detail::region<Container> reg)
: type_(value_t::local_time),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->local_time_, lt);
}
template<typename Container>
basic_value(const local_datetime& ldt, detail::region<Container> reg)
: type_(value_t::local_datetime),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->local_datetime_, ldt);
}
template<typename Container>
basic_value(const offset_datetime& odt, detail::region<Container> reg)
: type_(value_t::offset_datetime),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->offset_datetime_, odt);
}
template<typename Container>
basic_value(const array_type& ary, detail::region<Container> reg)
: type_(value_t::array),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->array_, ary);
}
template<typename Container>
basic_value(const table_type& tab, detail::region<Container> reg)
: type_(value_t::table),
region_info_(std::make_shared<detail::region<Container>>(std::move(reg))),
comments_(region_info_->comments())
{
assigner(this->table_, tab);
}
template<typename T, typename Container, typename std::enable_if< template<typename T, typename Container, typename std::enable_if<
detail::is_exact_toml_type<T, value_type>::value, detail::is_exact_toml_type<T, value_type>::value,
@@ -1247,7 +1248,7 @@ class basic_value
bool is_array() const noexcept {return this->is(value_t::array );} bool is_array() const noexcept {return this->is(value_t::array );}
bool is_table() const noexcept {return this->is(value_t::table );} bool is_table() const noexcept {return this->is(value_t::table );}
value_t type() const {return type_;} value_t type() const noexcept {return type_;}
template<value_t T> template<value_t T>
typename detail::enum_to_type<T, value_type>::type& cast() & typename detail::enum_to_type<T, value_type>::type& cast() &
@@ -1606,6 +1607,101 @@ class basic_value
return this->as_array(std::nothrow)[idx]; return this->as_array(std::nothrow)[idx];
} }
void push_back(const value_type& x)
{
if(this->type_ != value_t::array)
{
throw type_error(detail::format_underline(
"toml::value::push_back(value): bad_cast to array type", {
{this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}), this->location());
}
this->as_array(std::nothrow).push_back(x);
return;
}
void push_back(value_type&& x)
{
if(this->type_ != value_t::array)
{
throw type_error(detail::format_underline(
"toml::value::push_back(value): bad_cast to array type", {
{this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}), this->location());
}
this->as_array(std::nothrow).push_back(std::move(x));
return;
}
template<typename ... Ts>
value_type& emplace_back(Ts&& ... args)
{
if(this->type_ != value_t::array)
{
throw type_error(detail::format_underline(
"toml::value::emplace_back(value): bad_cast to array type", {
{this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}), this->location());
}
this->as_array(std::nothrow).emplace_back(std::forward<Ts>(args) ...);
return this->as_array(std::nothrow).back();
}
std::size_t size() const
{
switch(this->type_)
{
case value_t::array:
{
return this->as_array().size();
}
case value_t::table:
{
return this->as_table().size();
}
case value_t::string:
{
return this->as_string().str.size();
}
default:
{
throw type_error(detail::format_underline(
"toml::value::size(): bad_cast to container types", {
{this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}), this->location());
}
}
}
std::size_t count(const key_type& k) const
{
if(this->type_ != value_t::table)
{
throw type_error(detail::format_underline(
"toml::value::count(key): bad_cast to table type", {
{this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}), this->location());
}
return this->as_table().count(k);
}
bool contains(const key_type& k) const
{
if(this->type_ != value_t::table)
{
throw type_error(detail::format_underline(
"toml::value::contains(key): bad_cast to table type", {
{this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}), this->location());
}
return (this->as_table().count(k) != 0);
}
source_location location() const source_location location() const
{ {
return source_location(this->region_info_.get()); return source_location(this->region_info_.get());
@@ -1899,77 +1995,5 @@ inline std::string format_error(const std::string& err_msg,
}, std::move(hints), colorize); }, std::move(hints), colorize);
} }
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, const toml::boolean&>
visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
{
switch(v.type())
{
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::floating : {return visitor(std::move(v.as_floating ()));}
case value_t::string : {return visitor(std::move(v.as_string ()));}
case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
case value_t::local_date : {return visitor(std::move(v.as_local_date ()));}
case value_t::local_time : {return visitor(std::move(v.as_local_time ()));}
case value_t::array : {return visitor(std::move(v.as_array ()));}
case value_t::table : {return visitor(std::move(v.as_table ()));}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
}// toml }// toml
#endif// TOML11_VALUE #endif// TOML11_VALUE

134
toml/visit.hpp Normal file
View File

@@ -0,0 +1,134 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_VISIT_HPP
#define TOML11_VISIT_HPP
#include "value.hpp"
namespace toml
{
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, const toml::boolean&>
visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
{
switch(v.type())
{
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::floating : {return visitor(std::move(v.as_floating ()));}
case value_t::string : {return visitor(std::move(v.as_string ()));}
case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
case value_t::local_date : {return visitor(std::move(v.as_local_date ()));}
case value_t::local_time : {return visitor(std::move(v.as_local_time ()));}
case value_t::array : {return visitor(std::move(v.as_array ()));}
case value_t::table : {return visitor(std::move(v.as_table ()));}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
namespace detail
{
template<typename Result, typename Visitor, typename Value>
struct visitor
{
template<typename ... Ts>
Result operator()(Ts&& ... args)
{
return vis(value, args ...);
}
Visitor vis;
Value value;
};
template<typename Result, typename Visitor, typename Value>
visitor<Result, Visitor, Value> make_visitor(Visitor&& vis, Value&& val)
{
return visitor<Result, Visitor, Value>{
std::forward<Visitor>(vis), std::forward<Value>(val)
};
}
} // detail
template<typename Visitor, typename Value, typename ... Values>
auto visit(Visitor&& visitor, Value&& v, Values&& ... vs)
-> detail::enable_if_t<detail::conjunction<
detail::is_basic_value<Value>, detail::is_basic_value<Values> ...
>::value, decltype(visitor(std::forward<Value >(v ).as_boolean(),
std::forward<Values>(vs).as_boolean()...))>
{
using result_t = decltype(visitor(v.as_boolean(), vs.as_boolean()...));
using detail::make_visitor;
switch(v.type())
{
case value_t::boolean : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_boolean ()), std::forward<Values>(vs)...);}
case value_t::integer : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_integer ()), std::forward<Values>(vs)...);}
case value_t::floating : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_floating ()), std::forward<Values>(vs)...);}
case value_t::string : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_string ()), std::forward<Values>(vs)...);}
case value_t::offset_datetime: {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_offset_datetime()), std::forward<Values>(vs)...);}
case value_t::local_datetime : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_datetime ()), std::forward<Values>(vs)...);}
case value_t::local_date : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_date ()), std::forward<Values>(vs)...);}
case value_t::local_time : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_time ()), std::forward<Values>(vs)...);}
case value_t::array : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_array ()), std::forward<Values>(vs)...);}
case value_t::table : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_table ()), std::forward<Values>(vs)...);}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
} // toml
#endif// TOML11_VISIT_HPP