mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac1130f9f4 | ||
|
|
d290c3b7e5 | ||
|
|
e4140ac1fd | ||
|
|
ef33c10ba8 | ||
|
|
ced710bb4c | ||
|
|
6b5944e839 | ||
|
|
76cae8c057 | ||
|
|
3930a44ccd | ||
|
|
3b6417de00 | ||
|
|
573a6f1d81 | ||
|
|
f6a41d986c | ||
|
|
16fc172b21 | ||
|
|
7d03eb489a | ||
|
|
0582e1535b | ||
|
|
d495df93a6 | ||
|
|
5ca3a3c262 | ||
|
|
aa8d574dfe | ||
|
|
49fdb61731 | ||
|
|
b2bb21a473 | ||
|
|
0c58549fc6 | ||
|
|
b7b5e847d3 | ||
|
|
22d630fec1 | ||
|
|
f7bf341452 | ||
|
|
0934d90f90 | ||
|
|
f2c8d0e279 | ||
|
|
8c7d83d985 | ||
|
|
5ce44adbdc | ||
|
|
5c5b1320d0 | ||
|
|
8b737dc21f | ||
|
|
ee654b6c3f | ||
|
|
c59782d180 | ||
|
|
9bef715ccd | ||
|
|
d2b1cf5123 | ||
|
|
9f92916d1d | ||
|
|
666e4cf9dc | ||
|
|
cafee29c64 | ||
|
|
a7a2272b29 | ||
|
|
dc0bca2bb6 | ||
|
|
490abe04fd | ||
|
|
81ed4c0e9d | ||
|
|
1b07baf184 | ||
|
|
9073d52159 | ||
|
|
55260654bf | ||
|
|
aa6271af75 | ||
|
|
c54a03f189 | ||
|
|
c153c0e8c3 | ||
|
|
1f90af8e67 | ||
|
|
a0c5192b74 | ||
|
|
7f020f3f44 | ||
|
|
827b433389 | ||
|
|
1148d01c70 | ||
|
|
17d78553ff | ||
|
|
4c12dad51f |
95
.travis.yml
95
.travis.yml
@@ -5,7 +5,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-5" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="g++-5" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -17,7 +17,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-6" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="g++-6" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -29,7 +29,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-7" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="g++-7" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -41,7 +41,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-8" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="g++-8" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -65,7 +65,19 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
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:
|
||||
apt:
|
||||
sources:
|
||||
@@ -89,7 +101,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-3.9" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="clang++-3.9" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -103,7 +115,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-4.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="clang++-4.0" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -117,7 +129,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-5.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="clang++-5.0" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -131,7 +143,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-6.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="clang++-6.0" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -145,7 +157,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-7" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="clang++-7" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -159,7 +171,7 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-8" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="clang++-8" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -187,7 +199,21 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
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:
|
||||
apt:
|
||||
sources:
|
||||
@@ -212,6 +238,34 @@ matrix:
|
||||
- clang-8
|
||||
- g++-8
|
||||
- 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
|
||||
language: cpp
|
||||
compiler: clang
|
||||
@@ -234,11 +288,26 @@ script:
|
||||
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
||||
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
||||
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
|
||||
- mkdir build
|
||||
- cd build
|
||||
- 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
|
||||
- ctest --output-on-failure
|
||||
|
||||
|
||||
@@ -4,21 +4,21 @@ enable_testing()
|
||||
project(toml11)
|
||||
|
||||
set(toml11_VERSION_MAYOR 3)
|
||||
set(toml11_VERSION_MINOR 2)
|
||||
set(toml11_VERSION_PATCH 0)
|
||||
set(toml11_VERSION_MINOR 3)
|
||||
set(toml11_VERSION_PATCH 1)
|
||||
set(toml11_VERSION
|
||||
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
||||
)
|
||||
|
||||
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)
|
||||
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
set(CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 11 CACHE STRING "The C++ standard whose features are requested to build all targets.")
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Boolean describing whether the value of CXX_STANDARD is a requirement.")
|
||||
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Boolean specifying whether compiler specific extensions are requested.")
|
||||
else()
|
||||
# Manually check for C++11 compiler flag.
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
|
||||
94
README.md
94
README.md
@@ -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");
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
If the value does not exist, `toml::find` throws an error with the location of
|
||||
the table.
|
||||
If the value does not exist, `toml::find` throws `std::out_of_range` with the
|
||||
location of the table.
|
||||
|
||||
```console
|
||||
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
|
||||
```
|
||||
|
||||
**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
|
||||
@@ -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
|
||||
from STL containers.
|
||||
from STL containers. In that case, the element type must be convertible to
|
||||
`toml::value`.
|
||||
|
||||
```cpp
|
||||
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
|
||||
|
||||
@@ -1093,7 +1133,7 @@ const auto data = toml::parse("example.toml");
|
||||
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.
|
||||
|
||||
@@ -1120,7 +1160,31 @@ struct foo
|
||||
In this way, because `toml::get` first constructs `foo` without arguments,
|
||||
the type should be default-constructible.
|
||||
|
||||
The second is to implement specialization of `toml::from` for your type.
|
||||
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
|
||||
namespace ext
|
||||
@@ -1719,11 +1783,15 @@ I appreciate the help of the contributors who introduced the great feature to th
|
||||
- Suppress warnings in Debug mode
|
||||
- OGAWA Kenichi (@kenichiice)
|
||||
- Suppress warnings on intel compiler
|
||||
- Jordan Williams (@jwillikers)
|
||||
- Fixed clang range-loop-analysis warnings
|
||||
- Fixed feature test macro to suppress -Wundef
|
||||
- Use cache variables in CMakeLists.txt
|
||||
|
||||
## Licensing terms
|
||||
|
||||
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.
|
||||
|
||||
@@ -39,6 +39,17 @@ set(TEST_NAMES
|
||||
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
|
||||
CHECK_CXX_COMPILER_FLAG("-Werror" COMPILER_SUPPORTS_WERROR)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-Wsign-conversion" COMPILER_SUPPORTS_WSIGN_CONVERSION)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wconversion" COMPILER_SUPPORTS_WCONVERSION)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wduplicated-cond" COMPILER_SUPPORTS_WDUPLICATED_COND)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wrange-loop-analysis" COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wundef" COMPILER_SUPPORTS_WUNDEF)
|
||||
|
||||
if(COMPILER_SUPPORTS_WALL)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
@@ -49,6 +60,36 @@ endif()
|
||||
if(COMPILER_SUPPORTS_WPEDANTIC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
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()
|
||||
if(COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wrange-loop-analysis")
|
||||
endif()
|
||||
if(COMPILER_SUPPORTS_WUNDEF)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wundef")
|
||||
endif()
|
||||
|
||||
option(TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
"use features in toml-lang/toml master while testing" OFF)
|
||||
@@ -104,6 +145,19 @@ foreach(TEST_NAME ${TEST_NAMES})
|
||||
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
|
||||
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
|
||||
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})
|
||||
|
||||
# Set the PATH to be able to find Boost DLL
|
||||
|
||||
@@ -84,9 +84,7 @@ struct json_serializer
|
||||
{
|
||||
if(!is_first) {std::cout << ", ";}
|
||||
is_first = false;
|
||||
std::cout << toml::format(toml::value(elem.first),
|
||||
std::numeric_limits<std::size_t>::max());
|
||||
std::cout << ':';
|
||||
std::cout << this->format_key(elem.first) << ':';
|
||||
toml::visit(*this, elem.second);
|
||||
}
|
||||
std::cout << '}';
|
||||
@@ -112,6 +110,12 @@ struct json_serializer
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string format_key(const std::string& s) const
|
||||
{
|
||||
const auto quote("\"");
|
||||
return quote + escape_string(s) + quote;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
|
||||
@@ -44,6 +44,18 @@ struct qux
|
||||
int a;
|
||||
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
|
||||
|
||||
namespace toml
|
||||
@@ -122,6 +134,19 @@ struct qux
|
||||
int a;
|
||||
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
|
||||
|
||||
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)
|
||||
{
|
||||
{
|
||||
@@ -384,5 +430,63 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
||||
BOOST_TEST(bars.at(2).b == "quux");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
// recursively search tables
|
||||
@@ -126,8 +198,76 @@ BOOST_AUTO_TEST_CASE(test_find_recursive)
|
||||
num2 = 42;
|
||||
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);
|
||||
|
||||
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}};
|
||||
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(v, "key"));
|
||||
BOOST_TEST(static_cast<double >(3.14) == toml::find<double >(v, "key"));
|
||||
BOOST_TEST(static_cast<long double>(3.14) == toml::find<long double>(v, "key"));
|
||||
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(std::move(v), "key"));
|
||||
const double ref(3.14);
|
||||
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(v, "key"));
|
||||
BOOST_TEST( ref == toml::find<double >(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));
|
||||
|
||||
std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key");
|
||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
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<unsigned>(69) == std::get<2>(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));
|
||||
|
||||
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(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
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<unsigned>(69) == std::get<2>(tpl));
|
||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||
|
||||
@@ -375,7 +375,8 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
|
||||
toml::value v1{{"key", 42}};
|
||||
toml::value v2{{"key", 3.14}};
|
||||
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}};
|
||||
@@ -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 moved2 = toml::find_or(std::move(v2), "key", 2.71f);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,11 +195,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_floating_type, value_type, test_value_typ
|
||||
{
|
||||
{
|
||||
value_type v(3.14);
|
||||
BOOST_TEST(static_cast<float >(3.14) == toml::get<float >(v));
|
||||
BOOST_TEST(static_cast<double >(3.14) == toml::get<double >(v));
|
||||
BOOST_TEST(static_cast<long double>(3.14) == toml::get<long double>(v));
|
||||
|
||||
BOOST_TEST(3.14f == toml::get<float>(std::move(v)));
|
||||
const double ref(3.14);
|
||||
BOOST_TEST(static_cast<float >(ref) == toml::get<float >(v));
|
||||
BOOST_TEST( ref == toml::get<double >(v));
|
||||
BOOST_TEST(static_cast<long double>(ref) == toml::get<long double>(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));
|
||||
|
||||
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
|
||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
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<unsigned>(69) == std::get<2>(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};
|
||||
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(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
}
|
||||
{
|
||||
value_type v{42, 54, 69, 72};
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
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<unsigned>(69) == std::get<2>(tpl));
|
||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||
|
||||
@@ -57,6 +57,22 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||
@@ -83,4 +99,16 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"''''That's still pointless', she said.'''",
|
||||
"''''That's still pointless', she said.'''");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"''''This,' she said, 'is just a pointless statement.''''",
|
||||
"''''This,' she said, 'is just a pointless statement.''''");
|
||||
}
|
||||
|
||||
@@ -29,16 +29,16 @@ BOOST_AUTO_TEST_CASE(test_string)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"The quick brown fox jumps over the lazy dog\"",
|
||||
toml::value("The quick brown fox jumps over the lazy dog", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\'The quick brown fox jumps over the lazy dog\'",
|
||||
toml::value("The quick brown fox jumps over the lazy dog", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"The quick brown fox \\\njumps over the lazy dog\"\"\"",
|
||||
toml::value("The quick brown fox jumps over the lazy dog", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''The quick brown fox \njumps over the lazy dog'''",
|
||||
toml::value("The quick brown fox \njumps over the lazy dog", string_t::literal));
|
||||
}
|
||||
@@ -69,14 +69,17 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\" And when \\\"'s are in the along with # \\\"\"",
|
||||
string(" And when \"'s are in the along with # \"", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"Here are fifteen apostrophes: '''''''''''''''\"",
|
||||
string("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_basic_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"GitHub Cofounder & CEO\\nLikes tater tots and beer.\"",
|
||||
value("GitHub Cofounder & CEO\nLikes tater tots and beer.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"192.168.1.1\"",
|
||||
value("192.168.1.1", string_t::basic));
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
@@ -84,16 +87,19 @@ BOOST_AUTO_TEST_CASE(test_basic_string_value)
|
||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"",
|
||||
value("\xE4\xB8\xAD\xE5\x9B\xBD", string_t::basic));
|
||||
#else
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"中国\"",
|
||||
value("中国", string_t::basic));
|
||||
#endif
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"You'll hate me after this - #\"",
|
||||
value("You'll hate me after this - #", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\" And when \\\"'s are in the along with # \\\"\"",
|
||||
value(" And when \"'s are in the along with # \"", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"Here are fifteen apostrophes: '''''''''''''''\"",
|
||||
value("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
||||
@@ -104,16 +110,41 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
|
||||
string("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
|
||||
string("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
|
||||
string("Here are three quotation marks: \"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
|
||||
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
|
||||
string("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ml_basic_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"\nThe quick brown \\\n\n fox jumps over \\\n the lazy dog.\"\"\"",
|
||||
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
|
||||
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
|
||||
value("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
|
||||
value("Here are three quotation marks: \"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
|
||||
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
|
||||
value("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||
@@ -134,16 +165,16 @@ BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_literal_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'C:\\Users\\nodejs\\templates'",
|
||||
value("C:\\Users\\nodejs\\templates", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'\\\\ServerX\\admin$\\system32\\'",
|
||||
value("\\\\ServerX\\admin$\\system32\\", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'Tom \"Dubs\" Preston-Werner'",
|
||||
value("Tom \"Dubs\" Preston-Werner", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'<\\i\\c*\\s*>'",
|
||||
value("<\\i\\c*\\s*>", string_t::literal));
|
||||
}
|
||||
@@ -156,16 +187,34 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
|
||||
string("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"''''That's still pointless', she said.'''",
|
||||
string("'That's still pointless', she said.", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
|
||||
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"''''This,' she said, 'is just a pointless statement.''''",
|
||||
string("'This,' she said, 'is just a pointless statement.'", string_t::literal));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ml_literal_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''I [dw]on't need \\d{2} apples'''",
|
||||
value("I [dw]on't need \\d{2} apples", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
|
||||
value("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"''''That's still pointless', she said.'''",
|
||||
value("'That's still pointless', she said.", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
|
||||
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"''''This,' she said, 'is just a pointless statement.''''",
|
||||
value("'This,' she said, 'is just a pointless statement.'", string_t::literal));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_unicode_escape_sequence)
|
||||
|
||||
@@ -966,3 +966,54 @@ BOOST_AUTO_TEST_CASE(test_value_bracket)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace toml
|
||||
namespace detail
|
||||
{
|
||||
// TODO: find more sophisticated way to handle this
|
||||
#if _POSIX_C_SOURCE >= 1 || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
@@ -35,7 +35,7 @@ inline std::tm gmtime_s(const std::time_t* src)
|
||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
#elif _MSC_VER
|
||||
#elif defined(_MSC_VER)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
@@ -172,9 +172,9 @@ template<typename charT, typename traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
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(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(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.day ) ;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace toml
|
||||
struct exception : public std::exception
|
||||
{
|
||||
public:
|
||||
exception(const source_location& loc): loc_(loc) {}
|
||||
explicit exception(const source_location& loc): loc_(loc) {}
|
||||
virtual ~exception() noexcept override = default;
|
||||
virtual const char* what() const noexcept override {return "";}
|
||||
virtual source_location const& location() const noexcept {return loc_;}
|
||||
|
||||
197
toml/get.hpp
197
toml/get.hpp
@@ -259,6 +259,15 @@ template<typename T, typename C,
|
||||
std::size_t S = sizeof(::toml::from<T>)>
|
||||
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.
|
||||
|
||||
@@ -417,6 +426,17 @@ T get(const basic_value<C, M, V>& 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
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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);
|
||||
|
||||
@@ -516,57 +582,152 @@ find(basic_value<C, M, V>&& v, const key& 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)
|
||||
|
||||
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 ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
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 ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
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 ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
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 ...> 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>&>()))
|
||||
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 ...> 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>&>()))
|
||||
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 ...> 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>&&>()))
|
||||
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)...);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -154,12 +154,53 @@ using lex_basic_string = sequence<lex_quotation_mark,
|
||||
repeat<lex_basic_char, unlimited>,
|
||||
lex_quotation_mark>;
|
||||
|
||||
// After toml post-v0.5.0, it is explicitly clarified how quotes in ml-strings
|
||||
// are allowed to be used.
|
||||
// After this, the following strings are *explicitly* allowed.
|
||||
// - One or two `"`s in a multi-line basic string is allowed wherever it is.
|
||||
// - Three consecutive `"`s in a multi-line basic string is considered as a delimiter.
|
||||
// - One or two `"`s can appear just before or after the delimiter.
|
||||
// ```toml
|
||||
// str4 = """Here are two quotation marks: "". Simple enough."""
|
||||
// str5 = """Here are three quotation marks: ""\"."""
|
||||
// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
|
||||
// str7 = """"This," she said, "is just a pointless statement.""""
|
||||
// ```
|
||||
// In the current implementation (v3.3.0), it is difficult to parse `str7` in
|
||||
// the above example. It is difficult to recognize `"` at the end of string body
|
||||
// collectly. It will be misunderstood as a `"""` delimiter and an additional,
|
||||
// invalid `"`. Like this:
|
||||
// ```console
|
||||
// what(): [error] toml::parse_table: invalid line format
|
||||
// --> hoge.toml
|
||||
// |
|
||||
// 13 | str7 = """"This," she said, "is just a pointless statement.""""
|
||||
// | ^- expected newline, but got '"'.
|
||||
// ```
|
||||
// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
|
||||
// splitted into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
|
||||
// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s.
|
||||
// In parse_ml_basic_string() function, the trailing `"`s will be attached to
|
||||
// the string body.
|
||||
//
|
||||
// Note: This feature is a "clarification". Therefore this change is considered
|
||||
// as a spec that has been defined since the time when the multi-line
|
||||
// basic string was introduced. Although it is a post-v0.5.0 changes,
|
||||
// this change will be activated regardless of the flag,
|
||||
// `TOML11_USE_UNRELEASED_TOML_FEATURES`.
|
||||
//
|
||||
using lex_ml_basic_string_delim = repeat<lex_quotation_mark, exactly<3>>;
|
||||
using lex_ml_basic_string_open = lex_ml_basic_string_delim;
|
||||
using lex_ml_basic_string_close = sequence<
|
||||
repeat<lex_quotation_mark, exactly<3>>,
|
||||
maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
|
||||
>;
|
||||
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09
|
||||
in_range<0x0a, 0x1F>, // is tab
|
||||
character<0x5C>,
|
||||
character<0x7F>,
|
||||
character<0x5C>, // backslash
|
||||
character<0x7F>, // DEL
|
||||
lex_ml_basic_string_delim>>;
|
||||
#else // TOML v0.5.0
|
||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00,0x1F>,
|
||||
@@ -176,9 +217,9 @@ using lex_ml_basic_char = either<lex_ml_basic_unescaped, lex_escaped>;
|
||||
using lex_ml_basic_body = repeat<either<lex_ml_basic_char, lex_newline,
|
||||
lex_ml_basic_escaped_newline>,
|
||||
unlimited>;
|
||||
using lex_ml_basic_string = sequence<lex_ml_basic_string_delim,
|
||||
using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
|
||||
lex_ml_basic_body,
|
||||
lex_ml_basic_string_delim>;
|
||||
lex_ml_basic_string_close>;
|
||||
|
||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
in_range<0x10, 0x19>, character<0x27>>>;
|
||||
@@ -187,7 +228,13 @@ using lex_literal_string = sequence<lex_apostrophe,
|
||||
repeat<lex_literal_char, unlimited>,
|
||||
lex_apostrophe>;
|
||||
|
||||
// the same reason as above.
|
||||
using lex_ml_literal_string_delim = repeat<lex_apostrophe, exactly<3>>;
|
||||
using lex_ml_literal_string_open = lex_ml_literal_string_delim;
|
||||
using lex_ml_literal_string_close = sequence<
|
||||
repeat<lex_apostrophe, exactly<3>>,
|
||||
maybe<lex_apostrophe>, maybe<lex_apostrophe>
|
||||
>;
|
||||
|
||||
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
in_range<0x10, 0x1F>,
|
||||
@@ -195,9 +242,9 @@ using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
lex_ml_literal_string_delim>>;
|
||||
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
|
||||
unlimited>;
|
||||
using lex_ml_literal_string = sequence<lex_ml_literal_string_delim,
|
||||
using lex_ml_literal_string = sequence<lex_ml_literal_string_open,
|
||||
lex_ml_literal_body,
|
||||
lex_ml_literal_string_delim>;
|
||||
lex_ml_literal_string_close>;
|
||||
|
||||
using lex_string = either<lex_ml_basic_string, lex_basic_string,
|
||||
lex_ml_literal_string, lex_literal_string>;
|
||||
|
||||
@@ -256,7 +256,7 @@ std::string read_utf8_codepoint(const region<Container>& reg,
|
||||
std::istringstream iss(str);
|
||||
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);
|
||||
return *reinterpret_cast<const char*>(std::addressof(uc));
|
||||
};
|
||||
@@ -375,7 +375,7 @@ parse_ml_basic_string(location<Container>& loc)
|
||||
std::string retval;
|
||||
retval.reserve(token.unwrap().size());
|
||||
|
||||
auto delim = lex_ml_basic_string_delim::invoke(inner_loc);
|
||||
auto delim = lex_ml_basic_string_open::invoke(inner_loc);
|
||||
if(!delim)
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
@@ -410,7 +410,26 @@ parse_ml_basic_string(location<Container>& loc)
|
||||
{{std::addressof(inner_loc), "not sufficient token"}}),
|
||||
source_location(std::addressof(inner_loc)));
|
||||
}
|
||||
delim = lex_ml_basic_string_delim::invoke(inner_loc);
|
||||
delim = lex_ml_basic_string_close::invoke(inner_loc);
|
||||
}
|
||||
// `lex_ml_basic_string_close` allows 3 to 5 `"`s to allow 1 or 2 `"`s
|
||||
// at just before the delimiter. Here, we need to attach `"`s at the
|
||||
// end of the string body, if it exists.
|
||||
// For detail, see the definition of `lex_ml_basic_string_close`.
|
||||
assert(std::all_of(delim.unwrap().first(), delim.unwrap().last(),
|
||||
[](const char c) noexcept {return c == '\"';}));
|
||||
switch(delim.unwrap().size())
|
||||
{
|
||||
case 3: {break;}
|
||||
case 4: {retval += "\""; break;}
|
||||
case 5: {retval += "\"\""; break;}
|
||||
default:
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
"parse_ml_basic_string: closing delimiter has invalid length",
|
||||
{{std::addressof(inner_loc), "end of this"}}),
|
||||
source_location(std::addressof(inner_loc)));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(toml::string(retval), token.unwrap()));
|
||||
}
|
||||
@@ -485,7 +504,7 @@ parse_ml_literal_string(location<Container>& loc)
|
||||
{
|
||||
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||
|
||||
const auto open = lex_ml_literal_string_delim::invoke(inner_loc);
|
||||
const auto open = lex_ml_literal_string_open::invoke(inner_loc);
|
||||
if(!open)
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
@@ -498,7 +517,7 @@ parse_ml_literal_string(location<Container>& loc)
|
||||
|
||||
const auto body = lex_ml_literal_body::invoke(inner_loc);
|
||||
|
||||
const auto close = lex_ml_literal_string_delim::invoke(inner_loc);
|
||||
const auto close = lex_ml_literal_string_close::invoke(inner_loc);
|
||||
if(!close)
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
@@ -506,9 +525,29 @@ parse_ml_literal_string(location<Container>& loc)
|
||||
{{std::addressof(inner_loc), "should be '''"}}),
|
||||
source_location(std::addressof(inner_loc)));
|
||||
}
|
||||
return ok(std::make_pair(
|
||||
toml::string(body.unwrap().str(), toml::string_t::literal),
|
||||
token.unwrap()));
|
||||
// `lex_ml_literal_string_close` allows 3 to 5 `'`s to allow 1 or 2 `'`s
|
||||
// at just before the delimiter. Here, we need to attach `'`s at the
|
||||
// end of the string body, if it exists.
|
||||
// For detail, see the definition of `lex_ml_basic_string_close`.
|
||||
|
||||
std::string retval = body.unwrap().str();
|
||||
assert(std::all_of(close.unwrap().first(), close.unwrap().last(),
|
||||
[](const char c) noexcept {return c == '\'';}));
|
||||
switch(close.unwrap().size())
|
||||
{
|
||||
case 3: {break;}
|
||||
case 4: {retval += "'"; break;}
|
||||
case 5: {retval += "''"; break;}
|
||||
default:
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
"parse_ml_literal_string: closing delimiter has invalid length",
|
||||
{{std::addressof(inner_loc), "end of this"}}),
|
||||
source_location(std::addressof(inner_loc)));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(toml::string(retval, toml::string_t::literal),
|
||||
token.unwrap()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -792,13 +831,13 @@ parse_offset_datetime(location<Container>& loc)
|
||||
const auto str = ofs.unwrap().str();
|
||||
if(str.front() == '+')
|
||||
{
|
||||
offset.hour = static_cast<std::int8_t>(from_string<int>(str.substr(1,2), 0));
|
||||
offset.minute = static_cast<std::int8_t>(from_string<int>(str.substr(4,2), 0));
|
||||
offset = time_offset(from_string<int>(str.substr(1,2), 0),
|
||||
from_string<int>(str.substr(4,2), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
offset.hour = -static_cast<std::int8_t>(from_string<int>(str.substr(1,2), 0));
|
||||
offset.minute = -static_cast<std::int8_t>(from_string<int>(str.substr(4,2), 0));
|
||||
offset = time_offset(-from_string<int>(str.substr(1,2), 0),
|
||||
-from_string<int>(str.substr(4,2), 0));
|
||||
}
|
||||
}
|
||||
else if(*inner_loc.iter() != 'Z' && *inner_loc.iter() != 'z')
|
||||
|
||||
@@ -511,7 +511,7 @@ inline std::string format_underline(const std::string& message,
|
||||
retval << '\n';
|
||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
||||
retval << color::bold << color::blue << " | " << color::reset;
|
||||
for(const auto help : helps)
|
||||
for(const auto& help : helps)
|
||||
{
|
||||
retval << color::bold << "\nHint: " << color::reset;
|
||||
retval << help;
|
||||
|
||||
@@ -119,12 +119,17 @@ struct serializer
|
||||
return token; // there is no exponent part. just return it.
|
||||
}
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
// Although currently it is not released yet, TOML will allow
|
||||
// zero-prefix in an exponent part such as 1.234e+01.
|
||||
// The following code removes the zero prefixes.
|
||||
// If the feature is activated, the following codes can be skipped.
|
||||
// Although currently it is not released yet as a tagged version,
|
||||
// TOML will allow zero-prefix in an exponent part, such as `1.234e+01`.
|
||||
// ```toml
|
||||
// num1 = 1.234e+1 # OK in TOML v0.5.0
|
||||
// num2 = 1.234e+01 # error in TOML v0.5.0 but will be allowed soon
|
||||
// ```
|
||||
// To avoid `e+01`, the following `else` section removes the zero
|
||||
// prefixes in the exponent part.
|
||||
// If the feature is activated, it can be skipped.
|
||||
return token;
|
||||
#endif
|
||||
#else
|
||||
// zero-prefix in an exponent is NOT allowed in TOML v0.5.0.
|
||||
// remove it if it exists.
|
||||
bool sign_exists = false;
|
||||
@@ -143,17 +148,29 @@ struct serializer
|
||||
zero_prefix);
|
||||
}
|
||||
return token;
|
||||
#endif
|
||||
}
|
||||
std::string operator()(const string_type& s) const
|
||||
{
|
||||
if(s.kind == string_t::basic)
|
||||
{
|
||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
|
||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend())
|
||||
{
|
||||
// if linefeed is contained, make it multiline-string.
|
||||
const std::string open("\"\"\"\n");
|
||||
const std::string close("\\\n\"\"\"");
|
||||
return open + this->escape_ml_basic_string(s.str) + close;
|
||||
// if linefeed or double-quote is contained,
|
||||
// make it multiline basic string.
|
||||
const auto escaped = this->escape_ml_basic_string(s.str);
|
||||
std::string open("\"\"\"");
|
||||
std::string close("\"\"\"");
|
||||
if(escaped.find('\n') != std::string::npos ||
|
||||
this->width_ < escaped.size() + 6)
|
||||
{
|
||||
// if the string body contains newline or is enough long,
|
||||
// add newlines after and before delimiters.
|
||||
open += "\n";
|
||||
close = std::string("\\\n") + close;
|
||||
}
|
||||
return open + escaped + close;
|
||||
}
|
||||
|
||||
// no linefeed. try to make it oneline-string.
|
||||
@@ -194,7 +211,11 @@ struct serializer
|
||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||
std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
|
||||
{
|
||||
const std::string open("'''\n");
|
||||
std::string open("'''");
|
||||
if(this->width_ + 6 < s.str.size())
|
||||
{
|
||||
open += '\n'; // the first newline is ignored by TOML spec
|
||||
}
|
||||
const std::string close("'''");
|
||||
return open + s.str + close;
|
||||
}
|
||||
@@ -489,7 +510,9 @@ struct serializer
|
||||
switch(*i)
|
||||
{
|
||||
case '\\': {retval += "\\\\"; break;}
|
||||
case '\"': {retval += "\\\""; break;}
|
||||
// One or two consecutive "s are allowed.
|
||||
// Later we will check there are no three consecutive "s.
|
||||
// case '\"': {retval += "\\\""; break;}
|
||||
case '\b': {retval += "\\b"; break;}
|
||||
case '\t': {retval += "\\t"; break;}
|
||||
case '\f': {retval += "\\f"; break;}
|
||||
@@ -510,6 +533,23 @@ struct serializer
|
||||
default: {retval += *i; break;}
|
||||
}
|
||||
}
|
||||
// Only 1 or 2 consecutive `"`s are allowed in multiline basic string.
|
||||
// 3 consecutive `"`s are considered as a closing delimiter.
|
||||
// We need to check if there are 3 or more consecutive `"`s and insert
|
||||
// backslash to break them down into several short `"`s like the `str6`
|
||||
// in the following example.
|
||||
// ```toml
|
||||
// str4 = """Here are two quotation marks: "". Simple enough."""
|
||||
// # str5 = """Here are three quotation marks: """.""" # INVALID
|
||||
// str5 = """Here are three quotation marks: ""\"."""
|
||||
// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
|
||||
// ```
|
||||
auto found_3_quotes = retval.find("\"\"\"");
|
||||
while(found_3_quotes != std::string::npos)
|
||||
{
|
||||
retval.replace(found_3_quotes, 3, "\"\"\\\"");
|
||||
found_3_quotes = retval.find("\"\"\"");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -579,7 +619,7 @@ struct serializer
|
||||
|
||||
// print non-table stuff first. because after printing [foo.bar], the
|
||||
// remaining non-table values will be assigned into [foo.bar], not [foo]
|
||||
for(const auto kv : v)
|
||||
for(const auto& kv : v)
|
||||
{
|
||||
if(kv.second.is_table() || is_array_of_tables(kv.second))
|
||||
{
|
||||
|
||||
@@ -16,10 +16,9 @@ struct storage
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
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 const& v): ptr(toml::make_unique<T>(v)) {}
|
||||
explicit storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
|
||||
~storage() = default;
|
||||
|
||||
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
|
||||
storage& operator=(const storage& rhs)
|
||||
{
|
||||
|
||||
@@ -111,6 +111,14 @@ struct has_into_toml_method
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 T> struct conjunction<T> : T{};
|
||||
template<typename T, typename ... Ts>
|
||||
@@ -128,6 +136,8 @@ struct disjunction<T, Ts...> :
|
||||
template<typename T>
|
||||
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
|
||||
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// type checkers
|
||||
|
||||
@@ -182,6 +192,13 @@ struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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<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>
|
||||
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
||||
|
||||
#endif // __cplusplus >= 2014
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++14 enable_if_t
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
|
||||
using std::enable_if_t;
|
||||
|
||||
#else
|
||||
|
||||
template<bool B, typename T>
|
||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
#endif // __cplusplus >= 2014
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// return_type_of_t
|
||||
|
||||
|
||||
@@ -20,12 +20,20 @@
|
||||
namespace toml
|
||||
{
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
|
||||
using std::make_unique;
|
||||
|
||||
#else
|
||||
|
||||
template<typename T, typename ... Ts>
|
||||
inline std::unique_ptr<T> make_unique(Ts&& ... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
|
||||
}
|
||||
|
||||
#endif // __cplusplus >= 2014
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
@@ -76,10 +84,10 @@ std::string concat_to_string(Ts&& ... args)
|
||||
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
T from_string(const std::string& str, U&& opt)
|
||||
template<typename T>
|
||||
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);
|
||||
iss >> v;
|
||||
return v;
|
||||
|
||||
270
toml/value.hpp
270
toml/value.hpp
@@ -529,14 +529,6 @@ class basic_value
|
||||
assigner(this->boolean_, b);
|
||||
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)
|
||||
: type_(value_t::boolean),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
@@ -557,19 +549,6 @@ class basic_value
|
||||
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<
|
||||
std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
|
||||
std::nullptr_t>::type = nullptr>
|
||||
@@ -604,15 +583,6 @@ class basic_value
|
||||
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<
|
||||
std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
|
||||
@@ -643,14 +613,6 @@ class basic_value
|
||||
{
|
||||
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)
|
||||
{
|
||||
this->cleanup();
|
||||
@@ -782,14 +744,6 @@ class basic_value
|
||||
{
|
||||
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)
|
||||
{
|
||||
this->cleanup();
|
||||
@@ -814,14 +768,6 @@ class basic_value
|
||||
{
|
||||
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)
|
||||
: type_(value_t::local_time),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
@@ -872,14 +818,6 @@ class basic_value
|
||||
{
|
||||
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)
|
||||
: type_(value_t::local_datetime),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
@@ -904,14 +842,6 @@ class basic_value
|
||||
{
|
||||
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)
|
||||
: type_(value_t::offset_datetime),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
@@ -958,14 +888,6 @@ class basic_value
|
||||
{
|
||||
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)
|
||||
: type_(value_t::array),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
@@ -1079,14 +1001,6 @@ class basic_value
|
||||
{
|
||||
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)
|
||||
: type_(value_t::table),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
@@ -1216,6 +1130,93 @@ class basic_value
|
||||
}
|
||||
|
||||
// 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<
|
||||
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_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>
|
||||
typename detail::enum_to_type<T, value_type>::type& cast() &
|
||||
@@ -1606,6 +1607,101 @@ class basic_value
|
||||
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
|
||||
{
|
||||
return source_location(this->region_info_.get());
|
||||
|
||||
Reference in New Issue
Block a user