mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfe5e50acf | ||
|
|
05077dee0c | ||
|
|
b9f1726e26 | ||
|
|
c583e38ebf | ||
|
|
388e9db32b |
48
.travis.yml
48
.travis.yml
@@ -2,30 +2,6 @@ dist: trusty
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-4.8" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-4.8
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-4.9" CXX_STANDARD=11
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-4.9
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
@@ -293,6 +269,16 @@ matrix:
|
||||
- os: osx
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: CXX_STANDARD=11
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/Library/Caches/Homebrew
|
||||
addons:
|
||||
homebrew:
|
||||
update: true
|
||||
packages:
|
||||
- cmake
|
||||
- boost
|
||||
|
||||
script:
|
||||
- |
|
||||
@@ -302,10 +288,6 @@ 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 [[ "${CXX_STANDARD}" == "" ]]; then
|
||||
export CXX_STANDARD="11"
|
||||
fi
|
||||
- |
|
||||
if [[ "${TOML_HEAD}" != "ON" ]]; then
|
||||
export TOML_HEAD="OFF"
|
||||
@@ -324,8 +306,14 @@ script:
|
||||
- cmake --version
|
||||
- mkdir build
|
||||
- cd build
|
||||
- echo "COMPILER = ${COMPILER}"
|
||||
- echo "CXX_STANDARD = ${CXX_STANDARD}"
|
||||
- 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} -Dtoml11_TEST_WITH_ASAN=${WITH_ASAN} -Dtoml11_TEST_WITH_UBSAN=${WITH_UBSAN} ..
|
||||
- make
|
||||
- ctest --output-on-failure
|
||||
|
||||
# https://stackoverflow.com/a/53331571
|
||||
before_cache:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
enable_testing()
|
||||
|
||||
project(toml11 VERSION 3.3.1)
|
||||
project(toml11)
|
||||
|
||||
set(toml11_VERSION_MAYOR 3)
|
||||
set(toml11_VERSION_MINOR 3)
|
||||
set(toml11_VERSION_PATCH 0)
|
||||
set(toml11_VERSION
|
||||
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
||||
)
|
||||
|
||||
option(toml11_BUILD_TEST "Build toml tests" ON)
|
||||
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
|
||||
@@ -9,9 +16,11 @@ option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
|
||||
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.")
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
set(CXX_STANDARD_REQUIRED ON)
|
||||
else()
|
||||
# Manually check for C++11 compiler flag.
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
|
||||
63
README.md
63
README.md
@@ -8,17 +8,16 @@ toml11
|
||||
[](LICENSE)
|
||||
[](https://doi.org/10.5281/zenodo.1209136)
|
||||
|
||||
toml11 is a C++11 (or later) header-only toml parser/encoder depending only on C++ standard library.
|
||||
toml11 is a C++11 header-only toml parser/encoder depending only on C++ standard library.
|
||||
|
||||
- It is compatible to the latest version of [TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md).
|
||||
- It optionally supports the [unreleased features](#unreleased-toml-features) in the master branch of toml-lang/toml.
|
||||
- It is one of the most TOML standard compliant libraries, tested with [the language agnostic test suite for TOML parsers by BurntSushi](https://github.com/BurntSushi/toml-test).
|
||||
- It shows highly informative error messages. You can see the error messages about invalid files at [CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||
- It has configurable container. You can use any random-access containers and key-value maps as backend containers.
|
||||
- It optionally preserves comments without any overhead.
|
||||
- It has configurable serializer that supports comments, inline tables, literal strings and multiline strings.
|
||||
- It supports user-defined type conversion from/into toml values.
|
||||
- It correctly handles UTF-8 sequences, with or without BOM, both on posix and Windows.
|
||||
compatible to the latest version of
|
||||
[TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md)
|
||||
after version 2.0.0.
|
||||
|
||||
It passes [the language agnostic test suite for TOML parsers by BurntSushi](https://github.com/BurntSushi/toml-test).
|
||||
Not only the test suite itself, a TOML reader/encoder also runs on [CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||
You can see the error messages about invalid files and serialization results of valid files at
|
||||
[CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||
|
||||
## Example
|
||||
|
||||
@@ -28,25 +27,15 @@ toml11 is a C++11 (or later) header-only toml parser/encoder depending only on C
|
||||
|
||||
int main()
|
||||
{
|
||||
auto data = toml::parse("example.toml");
|
||||
const auto data = toml::parse("example.toml");
|
||||
|
||||
// find a value with the specified type from a table
|
||||
// title = "an example toml file"
|
||||
std::string title = toml::find<std::string>(data, "title");
|
||||
std::cout << "the title is " << title << std::endl;
|
||||
|
||||
// convert the whole array into any container automatically
|
||||
std::vector<int> nums = toml::find<std::vector<int>>(data, "nums");
|
||||
|
||||
// access with STL-like manner
|
||||
if(not data.at("a").contains("b"))
|
||||
{
|
||||
data["a"]["b"] = "c";
|
||||
}
|
||||
|
||||
// pass a fallback
|
||||
std::string name = toml::find_or<std::string>(data, "name", "not found");
|
||||
|
||||
// width-dependent formatting
|
||||
std::cout << std::setw(80) << data << std::endl;
|
||||
// nums = [1, 2, 3, 4, 5]
|
||||
std::vector<int> nums = toml::find<std::vector<int>>(data, "nums");
|
||||
std::cout << "the length of `nums` is" << nums.size() << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1424,7 +1413,7 @@ const toml::source_location loc = v.location();
|
||||
|
||||
## Exceptions
|
||||
|
||||
The following `exception` classes inherits `toml::exception` that inherits
|
||||
All the exceptions thrown by toml11 inherits `toml::exception` that inherits
|
||||
`std::exception`.
|
||||
|
||||
```cpp
|
||||
@@ -1451,16 +1440,6 @@ struct exception : public std::exception
|
||||
|
||||
It represents where the error occurs.
|
||||
|
||||
`syntax_error` will be thrown from `toml::parse` and `_toml` literal.
|
||||
`type_error` will be thrown from `toml::get/find`, `toml::value::as_xxx()`, and
|
||||
other functions that takes a content inside of `toml::value`.
|
||||
|
||||
Note that, currently, from `toml::value::at()` and `toml::find(value, key)`
|
||||
may throw an `std::out_of_range` that does not inherits `toml::exception`.
|
||||
|
||||
Also, in some cases, most likely in the file open error, it will throw an
|
||||
`std::runtime_error`.
|
||||
|
||||
## Colorize Error Messages
|
||||
|
||||
By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from
|
||||
@@ -1764,12 +1743,13 @@ Such a big change will not happen in the coming years.
|
||||
|
||||
## Running Tests
|
||||
|
||||
After cloning this repository, run the following command (thank you @jwillikers
|
||||
for automating test set fetching!).
|
||||
To run test codes, you need to clone toml-lang/toml repository under `build/` directory
|
||||
because some of the test codes read a file in the repository.
|
||||
|
||||
```sh
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ git clone https://github.com/toml-lang/toml.git
|
||||
$ cmake ..
|
||||
$ make
|
||||
$ make test
|
||||
@@ -1803,11 +1783,6 @@ 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
|
||||
- Automate test set fetching, update and refactor CMakeLists.txt
|
||||
|
||||
## Licensing terms
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@ build_script:
|
||||
- cd C:\toml11
|
||||
- mkdir build
|
||||
- cd build
|
||||
- git clone https://github.com/toml-lang/toml.git
|
||||
- file --mime-encoding toml/tests/hard_example_unicode.toml
|
||||
- cmake -G"%generator%" -DBOOST_ROOT=C:/Libraries/boost_1_69_0 ..
|
||||
- cmake --build . --config "%configuration%"
|
||||
- file --mime-encoding tests/toml/tests/hard_example_unicode.toml
|
||||
|
||||
test_script:
|
||||
- ctest --build-config "%configuration%" --timeout 300 --output-on-failure
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(toml
|
||||
SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/toml
|
||||
GIT_REPOSITORY https://github.com/toml-lang/toml
|
||||
GIT_TAG v0.5.0
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
set(TEST_NAMES
|
||||
test_datetime
|
||||
test_string
|
||||
@@ -43,6 +34,7 @@ set(TEST_NAMES
|
||||
test_error_detection
|
||||
test_format_error
|
||||
test_extended_conversions
|
||||
test_visit
|
||||
)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
||||
@@ -57,8 +49,6 @@ CHECK_CXX_COMPILER_FLAG("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BR
|
||||
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")
|
||||
@@ -93,12 +83,6 @@ 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)
|
||||
@@ -167,7 +151,7 @@ foreach(TEST_NAME ${TEST_NAMES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
|
||||
# Set the PATH to be able to find Boost DLL
|
||||
if(WIN32)
|
||||
|
||||
@@ -84,7 +84,9 @@ struct json_serializer
|
||||
{
|
||||
if(!is_first) {std::cout << ", ";}
|
||||
is_first = false;
|
||||
std::cout << this->format_key(elem.first) << ':';
|
||||
std::cout << toml::format(toml::value(elem.first),
|
||||
std::numeric_limits<std::size_t>::max());
|
||||
std::cout << ':';
|
||||
toml::visit(*this, elem.second);
|
||||
}
|
||||
std::cout << '}';
|
||||
@@ -110,12 +112,6 @@ 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()
|
||||
|
||||
@@ -57,22 +57,6 @@ 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)
|
||||
@@ -99,16 +83,4 @@ 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,17 +69,14 @@ 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)
|
||||
@@ -87,19 +84,16 @@ 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)
|
||||
@@ -110,41 +104,16 @@ 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)
|
||||
@@ -165,16 +134,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));
|
||||
}
|
||||
@@ -187,34 +156,16 @@ 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)
|
||||
|
||||
172
tests/test_visit.cpp
Normal file
172
tests/test_visit.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
#define BOOST_TEST_MODULE "test_visit"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include <toml.hpp>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
using test_value_types = std::tuple<
|
||||
toml::value,
|
||||
toml::basic_value<toml::preserve_comments>,
|
||||
toml::basic_value<toml::discard_comments, std::map, std::deque>,
|
||||
toml::basic_value<toml::preserve_comments, std::map, std::deque>
|
||||
>;
|
||||
|
||||
template<typename Value>
|
||||
struct visitor1
|
||||
{
|
||||
std::string operator()(const toml::boolean&) const {return "boolean";}
|
||||
std::string operator()(const toml::integer&) const {return "integer";}
|
||||
std::string operator()(const toml::floating&) const {return "floating";}
|
||||
std::string operator()(const toml::string&) const {return "string";}
|
||||
std::string operator()(const toml::local_time&) const {return "local_time";}
|
||||
std::string operator()(const toml::local_date&) const {return "local_date";}
|
||||
std::string operator()(const toml::local_datetime&) const {return "local_datetime";}
|
||||
std::string operator()(const toml::offset_datetime&) const {return "offset_datetime";}
|
||||
std::string operator()(const typename Value::array_type&) const {return "array";}
|
||||
std::string operator()(const typename Value::table_type&) const {return "table";}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_one, value_type, test_value_types)
|
||||
{
|
||||
{
|
||||
const value_type v(true);
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "boolean");
|
||||
}
|
||||
{
|
||||
const value_type v(42);
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "integer");
|
||||
}
|
||||
{
|
||||
const value_type v(3.14);
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "floating");
|
||||
}
|
||||
{
|
||||
const value_type v("foo");
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "string");
|
||||
}
|
||||
{
|
||||
const value_type v(toml::local_date(2018, toml::month_t::Apr, 22));
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_date");
|
||||
}
|
||||
{
|
||||
const value_type v(toml::local_time(12, 34, 56));
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_time");
|
||||
}
|
||||
{
|
||||
const value_type v(toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 22),
|
||||
toml::local_time(12, 34, 56)));
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_datetime");
|
||||
}
|
||||
{
|
||||
const value_type v(toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 22),
|
||||
toml::local_time(12, 34, 56),
|
||||
toml::time_offset(9, 0)));
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "offset_datetime");
|
||||
}
|
||||
{
|
||||
const value_type v{1,2,3,4,5};
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "array");
|
||||
}
|
||||
{
|
||||
const value_type v{
|
||||
{"foo", 42}, {"bar", "baz"}
|
||||
};
|
||||
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "table");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
struct visitor2
|
||||
{
|
||||
template<typename T1, typename T2>
|
||||
std::string operator()(const T1& v1, const T2& v2) const
|
||||
{
|
||||
visitor1<Value> vis;
|
||||
return vis(v1) + "+" + vis(v2);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_two, value_type, test_value_types)
|
||||
{
|
||||
std::vector<value_type> vs;
|
||||
vs.push_back(value_type(true));
|
||||
vs.push_back(value_type(42));
|
||||
vs.push_back(value_type(3.14));
|
||||
vs.push_back(value_type("foo"));
|
||||
vs.push_back(value_type(toml::local_date(2018, toml::month_t::Apr, 22)));
|
||||
vs.push_back(value_type(toml::local_time(12, 34, 56)));
|
||||
vs.push_back(value_type(toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 22),
|
||||
toml::local_time(12, 34, 56))));
|
||||
vs.push_back(value_type(toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 22),
|
||||
toml::local_time(12, 34, 56),
|
||||
toml::time_offset(9, 0))));
|
||||
vs.push_back(value_type{1,2,3,4,5});
|
||||
vs.push_back(value_type{{"foo", 42}, {"bar", "baz"}});
|
||||
|
||||
for(const auto& v1 : vs)
|
||||
{
|
||||
const auto t1 = toml::visit(visitor1<value_type>{}, v1);
|
||||
for(const auto& v2 : vs)
|
||||
{
|
||||
const auto t2 = toml::visit(visitor1<value_type>{}, v2);
|
||||
BOOST_TEST(toml::visit(visitor2<value_type>{}, v1, v2) ==
|
||||
t1 + "+" + t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
struct visitor3
|
||||
{
|
||||
template<typename T1, typename T2, typename T3>
|
||||
std::string operator()(const T1& v1, const T2& v2, const T3& v3) const
|
||||
{
|
||||
visitor1<Value> vis;
|
||||
return vis(v1) + "+" + vis(v2) + "+" + vis(v3);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_three, value_type, test_value_types)
|
||||
{
|
||||
std::vector<value_type> vs;
|
||||
vs.push_back(value_type(true));
|
||||
vs.push_back(value_type(42));
|
||||
vs.push_back(value_type(3.14));
|
||||
vs.push_back(value_type("foo"));
|
||||
vs.push_back(value_type(toml::local_date(2018, toml::month_t::Apr, 22)));
|
||||
vs.push_back(value_type(toml::local_time(12, 34, 56)));
|
||||
vs.push_back(value_type(toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 22),
|
||||
toml::local_time(12, 34, 56))));
|
||||
vs.push_back(value_type(toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Apr, 22),
|
||||
toml::local_time(12, 34, 56),
|
||||
toml::time_offset(9, 0))));
|
||||
vs.push_back(value_type{1,2,3,4,5});
|
||||
vs.push_back(value_type{{"foo", 42}, {"bar", "baz"}});
|
||||
|
||||
for(const auto& v1 : vs)
|
||||
{
|
||||
const auto t1 = toml::visit(visitor1<value_type>{}, v1);
|
||||
for(const auto& v2 : vs)
|
||||
{
|
||||
const auto t2 = toml::visit(visitor1<value_type>{}, v2);
|
||||
for(const auto& v3 : vs)
|
||||
{
|
||||
const auto t3 = toml::visit(visitor1<value_type>{}, v3);
|
||||
BOOST_TEST(toml::visit(visitor3<value_type>{}, v1, v2, v3) ==
|
||||
t1 + "+" + t2 + "+" + t3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,54 +81,6 @@ struct preserve_comments
|
||||
void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}
|
||||
void assign(size_type n, const std::string& val) {comments.assign(n, val);}
|
||||
|
||||
// Related to the issue #97.
|
||||
//
|
||||
// It is known that `std::vector::insert` and `std::vector::erase` in
|
||||
// the standard library implementation included in GCC 4.8.5 takes
|
||||
// `std::vector::iterator` instead of `std::vector::const_iterator`.
|
||||
// Because of the const-correctness, we cannot convert a `const_iterator` to
|
||||
// an `iterator`. It causes compilation error in GCC 4.8.5.
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
|
||||
# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
|
||||
# define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
|
||||
iterator insert(iterator p, const std::string& x)
|
||||
{
|
||||
return comments.insert(p, x);
|
||||
}
|
||||
iterator insert(iterator p, std::string&& x)
|
||||
{
|
||||
return comments.insert(p, std::move(x));
|
||||
}
|
||||
void insert(iterator p, size_type n, const std::string& x)
|
||||
{
|
||||
return comments.insert(p, n, x);
|
||||
}
|
||||
template<typename InputIterator>
|
||||
void insert(iterator p, InputIterator first, InputIterator last)
|
||||
{
|
||||
return comments.insert(p, first, last);
|
||||
}
|
||||
void insert(iterator p, std::initializer_list<std::string> ini)
|
||||
{
|
||||
return comments.insert(p, ini);
|
||||
}
|
||||
|
||||
template<typename ... Ts>
|
||||
iterator emplace(iterator p, Ts&& ... args)
|
||||
{
|
||||
return comments.emplace(p, std::forward<Ts>(args)...);
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) {return comments.erase(pos);}
|
||||
iterator erase(iterator first, iterator last)
|
||||
{
|
||||
return comments.erase(first, last);
|
||||
}
|
||||
#else
|
||||
iterator insert(const_iterator p, const std::string& x)
|
||||
{
|
||||
return comments.insert(p, x);
|
||||
@@ -162,7 +114,6 @@ struct preserve_comments
|
||||
{
|
||||
return comments.erase(first, last);
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(preserve_comments& other) {comments.swap(other.comments);}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace toml
|
||||
namespace detail
|
||||
{
|
||||
// TODO: find more sophisticated way to handle this
|
||||
#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
#if _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 defined(_MSC_VER)
|
||||
#elif _MSC_VER
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
|
||||
30
toml/get.hpp
30
toml/get.hpp
@@ -449,7 +449,10 @@ basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
||||
const auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return tab.at(ky);
|
||||
}
|
||||
@@ -460,7 +463,10 @@ basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
||||
auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return tab.at(ky);
|
||||
}
|
||||
@@ -471,7 +477,10 @@ basic_value<C, M, V> find(basic_value<C, M, V>&& v, const key& ky)
|
||||
typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return basic_value<C, M, V>(std::move(tab.at(ky)));
|
||||
}
|
||||
@@ -533,7 +542,10 @@ find(const basic_value<C, M, V>& v, const key& ky)
|
||||
const auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return ::toml::get<T>(tab.at(ky));
|
||||
}
|
||||
@@ -546,7 +558,10 @@ find(basic_value<C, M, V>& v, const key& ky)
|
||||
auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return ::toml::get<T>(tab.at(ky));
|
||||
}
|
||||
@@ -559,7 +574,10 @@ find(basic_value<C, M, V>&& v, const key& ky)
|
||||
typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return ::toml::get<T>(std::move(tab.at(ky)));
|
||||
}
|
||||
|
||||
@@ -154,53 +154,12 @@ 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>, // backslash
|
||||
character<0x7F>, // DEL
|
||||
character<0x5C>,
|
||||
character<0x7F>,
|
||||
lex_ml_basic_string_delim>>;
|
||||
#else // TOML v0.5.0
|
||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00,0x1F>,
|
||||
@@ -217,9 +176,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_open,
|
||||
using lex_ml_basic_string = sequence<lex_ml_basic_string_delim,
|
||||
lex_ml_basic_body,
|
||||
lex_ml_basic_string_close>;
|
||||
lex_ml_basic_string_delim>;
|
||||
|
||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
in_range<0x10, 0x19>, character<0x27>>>;
|
||||
@@ -228,13 +187,7 @@ 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>,
|
||||
@@ -242,9 +195,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_open,
|
||||
using lex_ml_literal_string = sequence<lex_ml_literal_string_delim,
|
||||
lex_ml_literal_body,
|
||||
lex_ml_literal_string_close>;
|
||||
lex_ml_literal_string_delim>;
|
||||
|
||||
using lex_string = either<lex_ml_basic_string, lex_basic_string,
|
||||
lex_ml_literal_string, lex_literal_string>;
|
||||
|
||||
@@ -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_open::invoke(inner_loc);
|
||||
auto delim = lex_ml_basic_string_delim::invoke(inner_loc);
|
||||
if(!delim)
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
@@ -410,26 +410,7 @@ 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_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)));
|
||||
}
|
||||
delim = lex_ml_basic_string_delim::invoke(inner_loc);
|
||||
}
|
||||
return ok(std::make_pair(toml::string(retval), token.unwrap()));
|
||||
}
|
||||
@@ -504,7 +485,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_open::invoke(inner_loc);
|
||||
const auto open = lex_ml_literal_string_delim::invoke(inner_loc);
|
||||
if(!open)
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
@@ -517,7 +498,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_close::invoke(inner_loc);
|
||||
const auto close = lex_ml_literal_string_delim::invoke(inner_loc);
|
||||
if(!close)
|
||||
{
|
||||
throw internal_error(format_underline(
|
||||
@@ -525,29 +506,9 @@ parse_ml_literal_string(location<Container>& loc)
|
||||
{{std::addressof(inner_loc), "should be '''"}}),
|
||||
source_location(std::addressof(inner_loc)));
|
||||
}
|
||||
// `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()));
|
||||
return ok(std::make_pair(
|
||||
toml::string(body.unwrap().str(), toml::string_t::literal),
|
||||
token.unwrap()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ struct region_base
|
||||
// number of characters in the line after the region
|
||||
virtual std::size_t after() const noexcept {return 0;}
|
||||
|
||||
virtual std::vector<std::string> comments() const {return {};}
|
||||
virtual std::vector<std::string> comments()const {return {};}
|
||||
// ```toml
|
||||
// # comment_before
|
||||
// key = "value" # comment_inline
|
||||
@@ -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;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define TOML11_SERIALIZER_HPP
|
||||
#include "value.hpp"
|
||||
#include "lexer.hpp"
|
||||
#include "visit.hpp"
|
||||
#include <limits>
|
||||
#include <cstdio>
|
||||
|
||||
@@ -22,62 +23,39 @@ namespace toml
|
||||
// Since toml restricts characters available in a bare key, generally a string
|
||||
// should be escaped. But checking whether a string needs to be surrounded by
|
||||
// a `"` and escaping some special character is boring.
|
||||
template<typename charT, typename traits, typename Alloc>
|
||||
std::basic_string<charT, traits, Alloc>
|
||||
format_key(const std::basic_string<charT, traits, Alloc>& key)
|
||||
inline std::string format_key(const toml::key& key)
|
||||
{
|
||||
// check the key can be a bare (unquoted) key
|
||||
detail::location<toml::key> loc(key, key);
|
||||
detail::lex_unquoted_key::invoke(loc);
|
||||
if(loc.iter() == loc.end())
|
||||
{
|
||||
return key; // all the tokens are consumed. the key is unquoted-key.
|
||||
}
|
||||
|
||||
//if it includes special characters, then format it in a "quoted" key.
|
||||
std::basic_string<charT, traits, Alloc> serialized("\"");
|
||||
std::string token("\"");
|
||||
for(const char c : key)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case '\\': {serialized += "\\\\"; break;}
|
||||
case '\"': {serialized += "\\\""; break;}
|
||||
case '\b': {serialized += "\\b"; break;}
|
||||
case '\t': {serialized += "\\t"; break;}
|
||||
case '\f': {serialized += "\\f"; break;}
|
||||
case '\n': {serialized += "\\n"; break;}
|
||||
case '\r': {serialized += "\\r"; break;}
|
||||
default : {serialized += c; break;}
|
||||
case '\\': {token += "\\\\"; break;}
|
||||
case '\"': {token += "\\\""; break;}
|
||||
case '\b': {token += "\\b"; break;}
|
||||
case '\t': {token += "\\t"; break;}
|
||||
case '\f': {token += "\\f"; break;}
|
||||
case '\n': {token += "\\n"; break;}
|
||||
case '\r': {token += "\\r"; break;}
|
||||
default : {token += c; break;}
|
||||
}
|
||||
}
|
||||
serialized += "\"";
|
||||
return serialized;
|
||||
token += "\"";
|
||||
return token;
|
||||
}
|
||||
|
||||
template<typename charT, typename traits, typename Alloc>
|
||||
std::basic_string<charT, traits, Alloc>
|
||||
format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
|
||||
{
|
||||
std::basic_string<charT, traits, Alloc> serialized;
|
||||
if(keys.empty()) {return serialized;}
|
||||
|
||||
for(const auto& ky : keys)
|
||||
{
|
||||
serialized += format_key(ky);
|
||||
serialized += charT('.');
|
||||
}
|
||||
serialized.pop_back(); // remove the last dot '.'
|
||||
return serialized;
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
template<typename Comment,
|
||||
template<typename ...> class Table,
|
||||
template<typename ...> class Array>
|
||||
struct serializer
|
||||
{
|
||||
static_assert(detail::is_basic_value<Value>::value,
|
||||
"toml::serializer is for toml::value and its variants, "
|
||||
"toml::basic_value<...>.");
|
||||
|
||||
using value_type = Value;
|
||||
using value_type = basic_value<Comment, Table, Array>;
|
||||
using key_type = typename value_type::key_type ;
|
||||
using comment_type = typename value_type::comment_type ;
|
||||
using boolean_type = typename value_type::boolean_type ;
|
||||
@@ -142,17 +120,12 @@ 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 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.
|
||||
// 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.
|
||||
return token;
|
||||
#else
|
||||
#endif
|
||||
// zero-prefix in an exponent is NOT allowed in TOML v0.5.0.
|
||||
// remove it if it exists.
|
||||
bool sign_exists = false;
|
||||
@@ -171,29 +144,17 @@ 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() ||
|
||||
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend())
|
||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
|
||||
{
|
||||
// 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;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// no linefeed. try to make it oneline-string.
|
||||
@@ -234,11 +195,7 @@ 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() )
|
||||
{
|
||||
std::string open("'''");
|
||||
if(this->width_ + 6 < s.str.size())
|
||||
{
|
||||
open += '\n'; // the first newline is ignored by TOML spec
|
||||
}
|
||||
const std::string open("'''\n");
|
||||
const std::string close("'''");
|
||||
return open + s.str + close;
|
||||
}
|
||||
@@ -293,7 +250,7 @@ struct serializer
|
||||
std::string token;
|
||||
if(!keys_.empty())
|
||||
{
|
||||
token += format_key(keys_.back());
|
||||
token += this->serialize_key(keys_.back());
|
||||
token += " = ";
|
||||
}
|
||||
bool failed = false;
|
||||
@@ -349,7 +306,7 @@ struct serializer
|
||||
}
|
||||
}
|
||||
token += "[[";
|
||||
token += format_keys(keys_);
|
||||
token += this->serialize_dotted_key(keys_);
|
||||
token += "]]\n";
|
||||
token += this->make_multiline_table(item.as_table());
|
||||
}
|
||||
@@ -461,7 +418,7 @@ struct serializer
|
||||
std::string token;
|
||||
if(!this->keys_.empty())
|
||||
{
|
||||
token += format_key(this->keys_.back());
|
||||
token += this->serialize_key(this->keys_.back());
|
||||
token += " = ";
|
||||
}
|
||||
token += this->make_inline_table(v);
|
||||
@@ -476,7 +433,7 @@ struct serializer
|
||||
if(!keys_.empty())
|
||||
{
|
||||
token += '[';
|
||||
token += format_keys(keys_);
|
||||
token += this->serialize_dotted_key(keys_);
|
||||
token += "]\n";
|
||||
}
|
||||
token += this->make_multiline_table(v);
|
||||
@@ -485,6 +442,25 @@ struct serializer
|
||||
|
||||
private:
|
||||
|
||||
std::string serialize_key(const toml::key& key) const
|
||||
{
|
||||
return ::toml::format_key(key);
|
||||
}
|
||||
|
||||
std::string serialize_dotted_key(const std::vector<toml::key>& keys) const
|
||||
{
|
||||
std::string token;
|
||||
if(keys.empty()){return token;}
|
||||
|
||||
for(const auto& k : keys)
|
||||
{
|
||||
token += this->serialize_key(k);
|
||||
token += '.';
|
||||
}
|
||||
token.erase(token.size() - 1, 1); // remove trailing `.`
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string escape_basic_string(const std::string& s) const
|
||||
{
|
||||
//XXX assuming `s` is a valid utf-8 sequence.
|
||||
@@ -514,9 +490,7 @@ struct serializer
|
||||
switch(*i)
|
||||
{
|
||||
case '\\': {retval += "\\\\"; break;}
|
||||
// One or two consecutive "s are allowed.
|
||||
// Later we will check there are no three consecutive "s.
|
||||
// case '\"': {retval += "\\\""; break;}
|
||||
case '\"': {retval += "\\\""; break;}
|
||||
case '\b': {retval += "\\b"; break;}
|
||||
case '\t': {retval += "\\t"; break;}
|
||||
case '\f': {retval += "\\f"; break;}
|
||||
@@ -537,23 +511,6 @@ 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;
|
||||
}
|
||||
|
||||
@@ -608,7 +565,7 @@ struct serializer
|
||||
{
|
||||
// in inline tables, trailing comma is not allowed (toml-lang #569).
|
||||
if(is_first) {is_first = false;} else {token += ',';}
|
||||
token += format_key(kv.first);
|
||||
token += this->serialize_key(kv.first);
|
||||
token += '=';
|
||||
token += visit(serializer(std::numeric_limits<std::size_t>::max(),
|
||||
this->float_prec_, true), kv.second);
|
||||
@@ -623,7 +580,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))
|
||||
{
|
||||
@@ -639,7 +596,7 @@ struct serializer
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
const auto key_and_sep = format_key(kv.first) + " = ";
|
||||
const auto key_and_sep = this->serialize_key(kv.first) + " = ";
|
||||
const auto residual_width = (this->width_ > key_and_sep.size()) ?
|
||||
this->width_ - key_and_sep.size() : 0;
|
||||
token += key_and_sep;
|
||||
@@ -721,7 +678,6 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
||||
int fprec = std::numeric_limits<toml::floating>::max_digits10,
|
||||
bool no_comment = false, bool force_inline = false)
|
||||
{
|
||||
using value_type = basic_value<C, M, V>;
|
||||
// if value is a table, it is considered to be a root object.
|
||||
// the root object can't be an inline table.
|
||||
if(v.is_table())
|
||||
@@ -732,10 +688,10 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
||||
oss << v.comments();
|
||||
oss << '\n'; // to split the file comment from the first element
|
||||
}
|
||||
oss << visit(serializer<value_type>(w, fprec, no_comment, false), v);
|
||||
oss << visit(serializer<C, M, V>(w, fprec, no_comment, false), v);
|
||||
return oss.str();
|
||||
}
|
||||
return visit(serializer<value_type>(w, fprec, force_inline), v);
|
||||
return visit(serializer<C, M, V>(w, fprec, force_inline), v);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -771,8 +727,6 @@ template<typename charT, typename traits, typename C,
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
|
||||
{
|
||||
using value_type = basic_value<C, M, V>;
|
||||
|
||||
// get status of std::setw().
|
||||
const auto w = static_cast<std::size_t>(os.width());
|
||||
const int fprec = static_cast<int>(os.precision());
|
||||
@@ -788,7 +742,7 @@ operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
|
||||
os << '\n'; // to split the file comment from the first element
|
||||
}
|
||||
// the root object can't be an inline table. so pass `false`.
|
||||
os << visit(serializer<value_type>(w, fprec, false, no_comment), v);
|
||||
os << visit(serializer<C, M, V>(w, fprec, false, no_comment), v);
|
||||
|
||||
// if v is a non-table value, and has only one comment, then
|
||||
// put a comment just after a value. in the following way.
|
||||
|
||||
664
toml/value.hpp
664
toml/value.hpp
@@ -20,145 +20,223 @@ namespace detail
|
||||
{
|
||||
|
||||
// to show error messages. not recommended for users.
|
||||
template<typename Value>
|
||||
inline region_base const& get_region(const Value& v)
|
||||
{
|
||||
return *(v.region_info_);
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
region_base const& get_region(const basic_value<C, T, A>&);
|
||||
template<typename Region,
|
||||
typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
void change_region(basic_value<C, T, A>&, Region&&);
|
||||
|
||||
template<typename Value, typename Region>
|
||||
void change_region(Value& v, Region&& reg)
|
||||
{
|
||||
using region_type = typename std::remove_reference<
|
||||
typename std::remove_cv<Region>::type
|
||||
>::type;
|
||||
|
||||
std::shared_ptr<region_base> new_reg =
|
||||
std::make_shared<region_type>(std::forward<region_type>(reg));
|
||||
v.region_info_ = new_reg;
|
||||
return;
|
||||
}
|
||||
|
||||
template<value_t Expected, typename Value>
|
||||
template<value_t Expected,
|
||||
typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
[[noreturn]] inline void
|
||||
throw_bad_cast(const std::string& funcname, value_t actual, const Value& v)
|
||||
throw_bad_cast(value_t actual, const ::toml::basic_value<C, T, A>& v)
|
||||
{
|
||||
throw type_error(detail::format_underline(
|
||||
concat_to_string(funcname, "bad_cast to ", Expected), {
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"toml::value: bad_cast to ", Expected), {
|
||||
{std::addressof(get_region(v)),
|
||||
concat_to_string("the actual type is ", actual)}
|
||||
}), v.location());
|
||||
}
|
||||
|
||||
// Throw `out_of_range` from `toml::value::at()` and `toml::find()`
|
||||
// after generating an error message.
|
||||
//
|
||||
// The implementation is a bit complicated and there are many edge-cases.
|
||||
// If you are not interested in the error message generation, just skip this.
|
||||
template<typename Value>
|
||||
[[noreturn]] void
|
||||
throw_key_not_found_error(const Value& v, const key& ky)
|
||||
{
|
||||
// The top-level table has its region at the first character of the file.
|
||||
// That means that, in the case when a key is not found in the top-level
|
||||
// table, the error message points to the first character. If the file has
|
||||
// its first table at the first line, the error message would be like this.
|
||||
// ```console
|
||||
// [error] key "a" not found
|
||||
// --> example.toml
|
||||
// |
|
||||
// 1 | [table]
|
||||
// | ^------ in this table
|
||||
// ```
|
||||
// It actually points to the top-level table at the first character,
|
||||
// not `[table]`. But it is too confusing. To avoid the confusion, the error
|
||||
// message should explicitly say "key not found in the top-level table".
|
||||
const auto& reg = get_region(v);
|
||||
if(reg.line_num() == "1" && reg.size() == 1)
|
||||
{
|
||||
// Here it assumes that top-level table starts at the first character.
|
||||
// The region corresponds to the top-level table will be generated at
|
||||
// `parse_toml_file` function.
|
||||
// It also assumes that the top-level table size is just one and
|
||||
// the line number is `1`. It is always satisfied. And those conditions
|
||||
// are satisfied only if the table is the top-level table.
|
||||
//
|
||||
// 1. one-character dot-key at the first line
|
||||
// ```toml
|
||||
// a.b = "c"
|
||||
// ```
|
||||
// toml11 counts whole key as the table key. Here, `a.b` is the region
|
||||
// of the table "a". It could be counter intuitive, but it works.
|
||||
// The size of the region is 3, not 1. The above example is the shortest
|
||||
// dot-key example. The size cannot be 1.
|
||||
//
|
||||
// 2. one-character inline-table at the first line
|
||||
// ```toml
|
||||
// a = {b = "c"}
|
||||
// ```
|
||||
// toml11 consideres the inline table body as the table region. Here,
|
||||
// `{b = "c"}` is the region of the table "a". The size of the region
|
||||
// is 9, not 1. The shotest inline table still has two characters, `{`
|
||||
// and `}`. The size cannot be 1.
|
||||
//
|
||||
// 3. one-character table declaration at the first line
|
||||
// ```toml
|
||||
// [a]
|
||||
// ```
|
||||
// toml11 consideres the whole table key as the table region. Here,
|
||||
// `[a]` is the table region. The size is 3, not 1.
|
||||
//
|
||||
throw std::out_of_range(format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found in the top-level table"), {
|
||||
{std::addressof(reg), "the top-level table starts here"}
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal table.
|
||||
throw std::out_of_range(format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(reg), "in this table"}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// switch by `value_t` at the compile time.
|
||||
// switch by `value_t` and call the corresponding `value::as_xxx()`. {{{
|
||||
template<value_t T>
|
||||
struct switch_cast {};
|
||||
#define TOML11_GENERATE_SWITCH_CASTER(TYPE) \
|
||||
template<> \
|
||||
struct switch_cast<value_t::TYPE> \
|
||||
{ \
|
||||
template<typename Value> \
|
||||
static typename Value::TYPE##_type& invoke(Value& v) \
|
||||
{ \
|
||||
return v.as_##TYPE(); \
|
||||
} \
|
||||
template<typename Value> \
|
||||
static typename Value::TYPE##_type const& invoke(const Value& v) \
|
||||
{ \
|
||||
return v.as_##TYPE(); \
|
||||
} \
|
||||
template<typename Value> \
|
||||
static typename Value::TYPE##_type&& invoke(Value&& v) \
|
||||
{ \
|
||||
return std::move(v).as_##TYPE(); \
|
||||
} \
|
||||
}; \
|
||||
/**/
|
||||
TOML11_GENERATE_SWITCH_CASTER(boolean)
|
||||
TOML11_GENERATE_SWITCH_CASTER(integer)
|
||||
TOML11_GENERATE_SWITCH_CASTER(floating)
|
||||
TOML11_GENERATE_SWITCH_CASTER(string)
|
||||
TOML11_GENERATE_SWITCH_CASTER(offset_datetime)
|
||||
TOML11_GENERATE_SWITCH_CASTER(local_datetime)
|
||||
TOML11_GENERATE_SWITCH_CASTER(local_date)
|
||||
TOML11_GENERATE_SWITCH_CASTER(local_time)
|
||||
TOML11_GENERATE_SWITCH_CASTER(array)
|
||||
TOML11_GENERATE_SWITCH_CASTER(table)
|
||||
|
||||
#undef TOML11_GENERATE_SWITCH_CASTER
|
||||
template<>
|
||||
struct switch_cast<value_t::boolean>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::boolean& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_boolean();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::boolean const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_boolean();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::boolean&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_boolean();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::integer>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::integer& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_integer();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::integer const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_integer();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::integer&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_integer();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::floating>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::floating& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_floating();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::floating const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_floating();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::floating&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_floating();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::string>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::string& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_string();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::string const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_string();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::string&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_string();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::offset_datetime>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::offset_datetime& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_offset_datetime();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::offset_datetime const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_offset_datetime();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::offset_datetime&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_offset_datetime();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::local_datetime>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_datetime& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_local_datetime();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_datetime const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_local_datetime();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_datetime&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_local_datetime();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::local_date>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_date& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_local_date();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_date const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_local_date();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_date&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_local_date();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::local_time>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_time& invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_local_time();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_time const& invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_local_time();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static ::toml::local_time&& invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_local_time();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::array>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static typename basic_value<C, T, A>::array_type&
|
||||
invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_array();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static typename basic_value<C, T, A>::array_type const&
|
||||
invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_array();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static typename basic_value<C, T, A>::array_type &&
|
||||
invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_array();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct switch_cast<value_t::table>
|
||||
{
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static typename basic_value<C, T, A>::table_type&
|
||||
invoke(basic_value<C, T, A>& v) noexcept
|
||||
{
|
||||
return v.as_table();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static typename basic_value<C, T, A>::table_type const&
|
||||
invoke(basic_value<C, T, A> const& v) noexcept
|
||||
{
|
||||
return v.as_table();
|
||||
}
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
static typename basic_value<C, T, A>::table_type &&
|
||||
invoke(basic_value<C, T, A>&& v) noexcept
|
||||
{
|
||||
return std::move(v).as_table();
|
||||
}
|
||||
}; // }}}
|
||||
|
||||
}// detail
|
||||
|
||||
@@ -1177,7 +1255,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != T)
|
||||
{
|
||||
detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
|
||||
detail::throw_bad_cast<T>(this->type_, *this);
|
||||
}
|
||||
return detail::switch_cast<T>::invoke(*this);
|
||||
}
|
||||
@@ -1186,7 +1264,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != T)
|
||||
{
|
||||
detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
|
||||
detail::throw_bad_cast<T>(this->type_, *this);
|
||||
}
|
||||
return detail::switch_cast<T>::invoke(*this);
|
||||
}
|
||||
@@ -1195,7 +1273,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != T)
|
||||
{
|
||||
detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
|
||||
detail::throw_bad_cast<T>(this->type_, *this);
|
||||
}
|
||||
return detail::switch_cast<T>::invoke(std::move(*this));
|
||||
}
|
||||
@@ -1239,14 +1317,13 @@ class basic_value
|
||||
// ========================================================================
|
||||
// throw version
|
||||
// ------------------------------------------------------------------------
|
||||
// const reference {{{
|
||||
// const reference
|
||||
|
||||
boolean const& as_boolean() const&
|
||||
{
|
||||
if(this->type_ != value_t::boolean)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::boolean>(
|
||||
"toml::value::as_boolean(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::boolean>(this->type_, *this);
|
||||
}
|
||||
return this->boolean_;
|
||||
}
|
||||
@@ -1254,8 +1331,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::integer)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::integer>(
|
||||
"toml::value::as_integer(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::integer>(this->type_, *this);
|
||||
}
|
||||
return this->integer_;
|
||||
}
|
||||
@@ -1263,8 +1339,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::floating)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::floating>(
|
||||
"toml::value::as_floating(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::floating>(this->type_, *this);
|
||||
}
|
||||
return this->floating_;
|
||||
}
|
||||
@@ -1272,8 +1347,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::string)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::string>(
|
||||
"toml::value::as_string(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::string>(this->type_, *this);
|
||||
}
|
||||
return this->string_;
|
||||
}
|
||||
@@ -1281,8 +1355,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::offset_datetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::offset_datetime>(
|
||||
"toml::value::as_offset_datetime(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::offset_datetime>(this->type_, *this);
|
||||
}
|
||||
return this->offset_datetime_;
|
||||
}
|
||||
@@ -1290,8 +1363,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_datetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_datetime>(
|
||||
"toml::value::as_local_datetime(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_datetime>(this->type_, *this);
|
||||
}
|
||||
return this->local_datetime_;
|
||||
}
|
||||
@@ -1299,8 +1371,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_date)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_date>(
|
||||
"toml::value::as_local_date(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_date>(this->type_, *this);
|
||||
}
|
||||
return this->local_date_;
|
||||
}
|
||||
@@ -1308,8 +1379,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_time)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_time>(
|
||||
"toml::value::as_local_time(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_time>(this->type_, *this);
|
||||
}
|
||||
return this->local_time_;
|
||||
}
|
||||
@@ -1317,8 +1387,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::as_array(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::array>(this->type_, *this);
|
||||
}
|
||||
return this->array_.value();
|
||||
}
|
||||
@@ -1326,21 +1395,19 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::as_table(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::table>(this->type_, *this);
|
||||
}
|
||||
return this->table_.value();
|
||||
}
|
||||
// }}}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// nonconst reference {{{
|
||||
// nonconst reference
|
||||
|
||||
boolean & as_boolean() &
|
||||
{
|
||||
if(this->type_ != value_t::boolean)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::boolean>(
|
||||
"toml::value::as_boolean(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::boolean>(this->type_, *this);
|
||||
}
|
||||
return this->boolean_;
|
||||
}
|
||||
@@ -1348,8 +1415,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::integer)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::integer>(
|
||||
"toml::value::as_integer(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::integer>(this->type_, *this);
|
||||
}
|
||||
return this->integer_;
|
||||
}
|
||||
@@ -1357,8 +1423,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::floating)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::floating>(
|
||||
"toml::value::as_floating(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::floating>(this->type_, *this);
|
||||
}
|
||||
return this->floating_;
|
||||
}
|
||||
@@ -1366,8 +1431,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::string)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::string>(
|
||||
"toml::value::as_string(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::string>(this->type_, *this);
|
||||
}
|
||||
return this->string_;
|
||||
}
|
||||
@@ -1375,8 +1439,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::offset_datetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::offset_datetime>(
|
||||
"toml::value::as_offset_datetime(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::offset_datetime>(this->type_, *this);
|
||||
}
|
||||
return this->offset_datetime_;
|
||||
}
|
||||
@@ -1384,8 +1447,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_datetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_datetime>(
|
||||
"toml::value::as_local_datetime(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_datetime>(this->type_, *this);
|
||||
}
|
||||
return this->local_datetime_;
|
||||
}
|
||||
@@ -1393,8 +1455,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_date)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_date>(
|
||||
"toml::value::as_local_date(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_date>(this->type_, *this);
|
||||
}
|
||||
return this->local_date_;
|
||||
}
|
||||
@@ -1402,8 +1463,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_time)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_time>(
|
||||
"toml::value::as_local_time(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_time>(this->type_, *this);
|
||||
}
|
||||
return this->local_time_;
|
||||
}
|
||||
@@ -1411,8 +1471,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::as_array(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::array>(this->type_, *this);
|
||||
}
|
||||
return this->array_.value();
|
||||
}
|
||||
@@ -1420,22 +1479,19 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::as_table(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::table>(this->type_, *this);
|
||||
}
|
||||
return this->table_.value();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// ------------------------------------------------------------------------
|
||||
// rvalue reference {{{
|
||||
// rvalue reference
|
||||
|
||||
boolean && as_boolean() &&
|
||||
{
|
||||
if(this->type_ != value_t::boolean)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::boolean>(
|
||||
"toml::value::as_boolean(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::boolean>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->boolean_);
|
||||
}
|
||||
@@ -1443,8 +1499,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::integer)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::integer>(
|
||||
"toml::value::as_integer(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::integer>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->integer_);
|
||||
}
|
||||
@@ -1452,8 +1507,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::floating)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::floating>(
|
||||
"toml::value::as_floating(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::floating>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->floating_);
|
||||
}
|
||||
@@ -1461,8 +1515,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::string)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::string>(
|
||||
"toml::value::as_string(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::string>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->string_);
|
||||
}
|
||||
@@ -1470,8 +1523,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::offset_datetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::offset_datetime>(
|
||||
"toml::value::as_offset_datetime(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::offset_datetime>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->offset_datetime_);
|
||||
}
|
||||
@@ -1479,8 +1531,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_datetime)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_datetime>(
|
||||
"toml::value::as_local_datetime(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_datetime>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->local_datetime_);
|
||||
}
|
||||
@@ -1488,8 +1539,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_date)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_date>(
|
||||
"toml::value::as_local_date(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_date>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->local_date_);
|
||||
}
|
||||
@@ -1497,8 +1547,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::local_time)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::local_time>(
|
||||
"toml::value::as_local_time(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::local_time>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->local_time_);
|
||||
}
|
||||
@@ -1506,8 +1555,7 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::as_array(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::array>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->array_.value());
|
||||
}
|
||||
@@ -1515,12 +1563,10 @@ class basic_value
|
||||
{
|
||||
if(this->type_ != value_t::table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::as_table(): ", this->type_, *this);
|
||||
detail::throw_bad_cast<value_t::table>(this->type_, *this);
|
||||
}
|
||||
return std::move(this->table_.value());
|
||||
}
|
||||
// }}}
|
||||
|
||||
// accessors =============================================================
|
||||
//
|
||||
@@ -1528,29 +1574,11 @@ class basic_value
|
||||
//
|
||||
value_type& at(const key& k)
|
||||
{
|
||||
if(!this->is_table())
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::at(key): ", this->type_, *this);
|
||||
}
|
||||
if(this->as_table(std::nothrow).count(k) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(*this, k);
|
||||
}
|
||||
return this->as_table(std::nothrow).at(k);
|
||||
return this->as_table().at(k);
|
||||
}
|
||||
value_type const& at(const key& k) const
|
||||
{
|
||||
if(!this->is_table())
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::at(key): ", this->type_, *this);
|
||||
}
|
||||
if(this->as_table(std::nothrow).count(k) == 0)
|
||||
{
|
||||
detail::throw_key_not_found_error(*this, k);
|
||||
}
|
||||
return this->as_table(std::nothrow).at(k);
|
||||
return this->as_table().at(k);
|
||||
}
|
||||
value_type& operator[](const key& k)
|
||||
{
|
||||
@@ -1558,78 +1586,49 @@ class basic_value
|
||||
{
|
||||
*this = table_type{};
|
||||
}
|
||||
else if(!this->is_table()) // initialized, but not a table
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::operator[](key): ", this->type_, *this);
|
||||
}
|
||||
return this->as_table(std::nothrow)[k];
|
||||
return this->as_table()[k];
|
||||
}
|
||||
|
||||
value_type& at(const std::size_t idx)
|
||||
{
|
||||
if(!this->is_array())
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::at(idx): ", this->type_, *this);
|
||||
}
|
||||
if(this->as_array(std::nothrow).size() <= idx)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(
|
||||
"toml::value::at(idx): no element corresponding to the index", {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the length is ", this->as_array(std::nothrow).size(),
|
||||
", and the specified index is ", idx)}
|
||||
}));
|
||||
}
|
||||
return this->as_array().at(idx);
|
||||
}
|
||||
value_type const& at(const std::size_t idx) const
|
||||
{
|
||||
if(!this->is_array())
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::at(idx): ", this->type_, *this);
|
||||
}
|
||||
if(this->as_array(std::nothrow).size() <= idx)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(
|
||||
"toml::value::at(idx): no element corresponding to the index", {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the length is ", this->as_array(std::nothrow).size(),
|
||||
", and the specified index is ", idx)}
|
||||
}));
|
||||
}
|
||||
return this->as_array(std::nothrow).at(idx);
|
||||
return this->as_array().at(idx);
|
||||
}
|
||||
|
||||
value_type& operator[](const std::size_t idx) noexcept
|
||||
{
|
||||
// no check...
|
||||
return this->as_array(std::nothrow)[idx];
|
||||
}
|
||||
value_type const& operator[](const std::size_t idx) const noexcept
|
||||
{
|
||||
// no check...
|
||||
return this->as_array(std::nothrow)[idx];
|
||||
}
|
||||
|
||||
void push_back(const value_type& x)
|
||||
{
|
||||
if(!this->is_array())
|
||||
if(this->type_ != value_t::array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::push_back(value): ", this->type_, *this);
|
||||
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->is_array())
|
||||
if(this->type_ != value_t::array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::push_back(value): ", this->type_, *this);
|
||||
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;
|
||||
@@ -1638,10 +1637,13 @@ class basic_value
|
||||
template<typename ... Ts>
|
||||
value_type& emplace_back(Ts&& ... args)
|
||||
{
|
||||
if(!this->is_array())
|
||||
if(this->type_ != value_t::array)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::array>(
|
||||
"toml::value::emplace_back(...): ", this->type_, *this);
|
||||
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();
|
||||
@@ -1653,15 +1655,15 @@ class basic_value
|
||||
{
|
||||
case value_t::array:
|
||||
{
|
||||
return this->as_array(std::nothrow).size();
|
||||
return this->as_array().size();
|
||||
}
|
||||
case value_t::table:
|
||||
{
|
||||
return this->as_table(std::nothrow).size();
|
||||
return this->as_table().size();
|
||||
}
|
||||
case value_t::string:
|
||||
{
|
||||
return this->as_string(std::nothrow).str.size();
|
||||
return this->as_string().str.size();
|
||||
}
|
||||
default:
|
||||
{
|
||||
@@ -1676,22 +1678,28 @@ class basic_value
|
||||
|
||||
std::size_t count(const key_type& k) const
|
||||
{
|
||||
if(!this->is_table())
|
||||
if(this->type_ != value_t::table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::count(key): ", this->type_, *this);
|
||||
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(std::nothrow).count(k);
|
||||
return this->as_table().count(k);
|
||||
}
|
||||
|
||||
bool contains(const key_type& k) const
|
||||
{
|
||||
if(!this->is_table())
|
||||
if(this->type_ != value_t::table)
|
||||
{
|
||||
detail::throw_bad_cast<value_t::table>(
|
||||
"toml::value::contains(key): ", this->type_, *this);
|
||||
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(std::nothrow).count(k) != 0);
|
||||
return (this->as_table().count(k) != 0);
|
||||
}
|
||||
|
||||
source_location location() const
|
||||
@@ -1716,11 +1724,13 @@ class basic_value
|
||||
}
|
||||
|
||||
// for error messages
|
||||
template<typename Value>
|
||||
friend region_base const& detail::get_region(const Value& v);
|
||||
template<typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
friend region_base const& detail::get_region(const basic_value<C, T, A>&);
|
||||
|
||||
template<typename Value, typename Region>
|
||||
friend void detail::change_region(Value& v, Region&& reg);
|
||||
template<typename Region, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
friend void detail::change_region(basic_value<C, T, A>&, Region&&);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1750,6 +1760,30 @@ using value = basic_value<discard_comments, std::unordered_map, std::vector>;
|
||||
using array = typename value::array_type;
|
||||
using table = typename value::table_type;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
inline region_base const& get_region(const basic_value<C, T, A>& v)
|
||||
{
|
||||
return *(v.region_info_);
|
||||
}
|
||||
|
||||
template<typename Region, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
void change_region(basic_value<C, T, A>& v, Region&& reg)
|
||||
{
|
||||
using region_type = typename std::remove_reference<
|
||||
typename std::remove_cv<Region>::type
|
||||
>::type;
|
||||
|
||||
std::shared_ptr<region_base> new_reg =
|
||||
std::make_shared<region_type>(std::forward<region_type>(reg));
|
||||
v.region_info_ = new_reg;
|
||||
return;
|
||||
}
|
||||
}// detail
|
||||
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
inline bool
|
||||
operator==(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
|
||||
@@ -1961,77 +1995,5 @@ inline std::string format_error(const std::string& err_msg,
|
||||
}, std::move(hints), colorize);
|
||||
}
|
||||
|
||||
template<typename Visitor, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
detail::return_type_of_t<Visitor, const toml::boolean&>
|
||||
visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::boolean : {return visitor(v.as_boolean ());}
|
||||
case value_t::integer : {return visitor(v.as_integer ());}
|
||||
case value_t::floating : {return visitor(v.as_floating ());}
|
||||
case value_t::string : {return visitor(v.as_string ());}
|
||||
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
|
||||
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
|
||||
case value_t::local_date : {return visitor(v.as_local_date ());}
|
||||
case value_t::local_time : {return visitor(v.as_local_time ());}
|
||||
case value_t::array : {return visitor(v.as_array ());}
|
||||
case value_t::table : {return visitor(v.as_table ());}
|
||||
case value_t::empty : break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
|
||||
"does not have any valid basic_value.", v, "here"));
|
||||
}
|
||||
|
||||
template<typename Visitor, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
detail::return_type_of_t<Visitor, toml::boolean&>
|
||||
visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::boolean : {return visitor(v.as_boolean ());}
|
||||
case value_t::integer : {return visitor(v.as_integer ());}
|
||||
case value_t::floating : {return visitor(v.as_floating ());}
|
||||
case value_t::string : {return visitor(v.as_string ());}
|
||||
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
|
||||
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
|
||||
case value_t::local_date : {return visitor(v.as_local_date ());}
|
||||
case value_t::local_time : {return visitor(v.as_local_time ());}
|
||||
case value_t::array : {return visitor(v.as_array ());}
|
||||
case value_t::table : {return visitor(v.as_table ());}
|
||||
case value_t::empty : break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
|
||||
"does not have any valid basic_value.", v, "here"));
|
||||
}
|
||||
|
||||
template<typename Visitor, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
detail::return_type_of_t<Visitor, toml::boolean&&>
|
||||
visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::boolean : {return visitor(std::move(v.as_boolean ()));}
|
||||
case value_t::integer : {return visitor(std::move(v.as_integer ()));}
|
||||
case value_t::floating : {return visitor(std::move(v.as_floating ()));}
|
||||
case value_t::string : {return visitor(std::move(v.as_string ()));}
|
||||
case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
|
||||
case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
|
||||
case value_t::local_date : {return visitor(std::move(v.as_local_date ()));}
|
||||
case value_t::local_time : {return visitor(std::move(v.as_local_time ()));}
|
||||
case value_t::array : {return visitor(std::move(v.as_array ()));}
|
||||
case value_t::table : {return visitor(std::move(v.as_table ()));}
|
||||
case value_t::empty : break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
|
||||
"does not have any valid basic_value.", v, "here"));
|
||||
}
|
||||
|
||||
}// toml
|
||||
#endif// TOML11_VALUE
|
||||
|
||||
134
toml/visit.hpp
Normal file
134
toml/visit.hpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright Toru Niina 2019.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_VISIT_HPP
|
||||
#define TOML11_VISIT_HPP
|
||||
#include "value.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template<typename Visitor, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
detail::return_type_of_t<Visitor, const toml::boolean&>
|
||||
visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::boolean : {return visitor(v.as_boolean ());}
|
||||
case value_t::integer : {return visitor(v.as_integer ());}
|
||||
case value_t::floating : {return visitor(v.as_floating ());}
|
||||
case value_t::string : {return visitor(v.as_string ());}
|
||||
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
|
||||
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
|
||||
case value_t::local_date : {return visitor(v.as_local_date ());}
|
||||
case value_t::local_time : {return visitor(v.as_local_time ());}
|
||||
case value_t::array : {return visitor(v.as_array ());}
|
||||
case value_t::table : {return visitor(v.as_table ());}
|
||||
case value_t::empty : break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
|
||||
"does not have any valid basic_value.", v, "here"));
|
||||
}
|
||||
|
||||
template<typename Visitor, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
detail::return_type_of_t<Visitor, toml::boolean&>
|
||||
visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::boolean : {return visitor(v.as_boolean ());}
|
||||
case value_t::integer : {return visitor(v.as_integer ());}
|
||||
case value_t::floating : {return visitor(v.as_floating ());}
|
||||
case value_t::string : {return visitor(v.as_string ());}
|
||||
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
|
||||
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
|
||||
case value_t::local_date : {return visitor(v.as_local_date ());}
|
||||
case value_t::local_time : {return visitor(v.as_local_time ());}
|
||||
case value_t::array : {return visitor(v.as_array ());}
|
||||
case value_t::table : {return visitor(v.as_table ());}
|
||||
case value_t::empty : break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
|
||||
"does not have any valid basic_value.", v, "here"));
|
||||
}
|
||||
|
||||
template<typename Visitor, typename C,
|
||||
template<typename ...> class T, template<typename ...> class A>
|
||||
detail::return_type_of_t<Visitor, toml::boolean&&>
|
||||
visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::boolean : {return visitor(std::move(v.as_boolean ()));}
|
||||
case value_t::integer : {return visitor(std::move(v.as_integer ()));}
|
||||
case value_t::floating : {return visitor(std::move(v.as_floating ()));}
|
||||
case value_t::string : {return visitor(std::move(v.as_string ()));}
|
||||
case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
|
||||
case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
|
||||
case value_t::local_date : {return visitor(std::move(v.as_local_date ()));}
|
||||
case value_t::local_time : {return visitor(std::move(v.as_local_time ()));}
|
||||
case value_t::array : {return visitor(std::move(v.as_array ()));}
|
||||
case value_t::table : {return visitor(std::move(v.as_table ()));}
|
||||
case value_t::empty : break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
|
||||
"does not have any valid basic_value.", v, "here"));
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Result, typename Visitor, typename Value>
|
||||
struct visitor
|
||||
{
|
||||
template<typename ... Ts>
|
||||
Result operator()(Ts&& ... args)
|
||||
{
|
||||
return vis(value, args ...);
|
||||
}
|
||||
Visitor vis;
|
||||
Value value;
|
||||
};
|
||||
|
||||
template<typename Result, typename Visitor, typename Value>
|
||||
visitor<Result, Visitor, Value> make_visitor(Visitor&& vis, Value&& val)
|
||||
{
|
||||
return visitor<Result, Visitor, Value>{
|
||||
std::forward<Visitor>(vis), std::forward<Value>(val)
|
||||
};
|
||||
}
|
||||
} // detail
|
||||
|
||||
template<typename Visitor, typename Value, typename ... Values>
|
||||
auto visit(Visitor&& visitor, Value&& v, Values&& ... vs)
|
||||
-> detail::enable_if_t<detail::conjunction<
|
||||
detail::is_basic_value<Value>, detail::is_basic_value<Values> ...
|
||||
>::value, decltype(visitor(std::forward<Value >(v ).as_boolean(),
|
||||
std::forward<Values>(vs).as_boolean()...))>
|
||||
{
|
||||
using result_t = decltype(visitor(v.as_boolean(), vs.as_boolean()...));
|
||||
using detail::make_visitor;
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::boolean : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_boolean ()), std::forward<Values>(vs)...);}
|
||||
case value_t::integer : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_integer ()), std::forward<Values>(vs)...);}
|
||||
case value_t::floating : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_floating ()), std::forward<Values>(vs)...);}
|
||||
case value_t::string : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_string ()), std::forward<Values>(vs)...);}
|
||||
case value_t::offset_datetime: {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_offset_datetime()), std::forward<Values>(vs)...);}
|
||||
case value_t::local_datetime : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_datetime ()), std::forward<Values>(vs)...);}
|
||||
case value_t::local_date : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_date ()), std::forward<Values>(vs)...);}
|
||||
case value_t::local_time : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_time ()), std::forward<Values>(vs)...);}
|
||||
case value_t::array : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_array ()), std::forward<Values>(vs)...);}
|
||||
case value_t::table : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_table ()), std::forward<Values>(vs)...);}
|
||||
case value_t::empty : break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
|
||||
"does not have any valid basic_value.", v, "here"));
|
||||
}
|
||||
|
||||
} // toml
|
||||
#endif// TOML11_VISIT_HPP
|
||||
Reference in New Issue
Block a user