mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a344668fa2 | ||
|
|
25aa97a435 | ||
|
|
af70d3dfed | ||
|
|
8b5cfb4105 | ||
|
|
4e0624aa60 | ||
|
|
3ac2c065eb | ||
|
|
470f81dc94 | ||
|
|
93a9f2711c | ||
|
|
761e576991 | ||
|
|
e6e84714c5 | ||
|
|
1efc99e11c | ||
|
|
92aa42a58e | ||
|
|
b1c9df8998 | ||
|
|
9633e5fe5a | ||
|
|
2164fd39f7 | ||
|
|
c22a3fd227 | ||
|
|
57c6652360 | ||
|
|
defde33544 | ||
|
|
46ed051740 | ||
|
|
2963d9a25b | ||
|
|
531f335417 | ||
|
|
f29f42277e | ||
|
|
b03cde566a | ||
|
|
57d4e196a3 | ||
|
|
deb3ab6617 | ||
|
|
bf992e8f94 | ||
|
|
7c07f4382c | ||
|
|
125f608fa5 | ||
|
|
4d0ed847f9 | ||
|
|
79594709fe | ||
|
|
55a738c11f | ||
|
|
eebe1f87e6 | ||
|
|
95c3b5f538 | ||
|
|
e2790c9e7b | ||
|
|
9b52dc0131 | ||
|
|
5212992f05 | ||
|
|
fcd6e47500 | ||
|
|
31826b55ce | ||
|
|
e3fc354e8d | ||
|
|
ea87f92358 | ||
|
|
c259456282 | ||
|
|
d7662347f2 | ||
|
|
5f5539d402 | ||
|
|
c2151cab0b | ||
|
|
653c87592c | ||
|
|
bdf4e75122 | ||
|
|
60d23116ba | ||
|
|
af8cf9ddc5 | ||
|
|
f125cca010 | ||
|
|
a20a2c0b80 | ||
|
|
9694afbe32 | ||
|
|
d11e42ca7e | ||
|
|
128b66bda9 | ||
|
|
d1af42f151 | ||
|
|
8acf105b56 | ||
|
|
b86b5364ba | ||
|
|
bfe57340f4 | ||
|
|
02a6f029ad | ||
|
|
9017900ff3 | ||
|
|
3c5ebd73d7 | ||
|
|
2223eb4f62 | ||
|
|
a655a71cef | ||
|
|
c34001725c | ||
|
|
5e3ffb70dd | ||
|
|
2265ca41c6 | ||
|
|
82fec38e37 | ||
|
|
189b910384 | ||
|
|
fe644ea4b7 | ||
|
|
4c34986db0 | ||
|
|
ac1130f9f4 | ||
|
|
d290c3b7e5 | ||
|
|
e4140ac1fd | ||
|
|
ef33c10ba8 | ||
|
|
ced710bb4c | ||
|
|
6b5944e839 | ||
|
|
76cae8c057 | ||
|
|
3930a44ccd | ||
|
|
3b6417de00 | ||
|
|
573a6f1d81 | ||
|
|
f6a41d986c | ||
|
|
16fc172b21 | ||
|
|
7d03eb489a | ||
|
|
0582e1535b | ||
|
|
d495df93a6 | ||
|
|
5ca3a3c262 |
@@ -12,7 +12,7 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
g++ --version
|
g++ --version
|
||||||
cd tests/
|
cd tests/
|
||||||
g++ -std=c++11 -O2 -Wall -Wextra -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_toml_test.cpp -o check_toml_test
|
g++ -std=c++11 -O2 -Wall -Wextra -Werror -DTOML11_DISALLOW_HETEROGENEOUS_ARRAYS -I../ check_toml_test.cpp -o check_toml_test
|
||||||
go get github.com/BurntSushi/toml-test
|
go get github.com/BurntSushi/toml-test
|
||||||
$GOPATH/bin/toml-test ./check_toml_test
|
$GOPATH/bin/toml-test ./check_toml_test
|
||||||
test_serialization:
|
test_serialization:
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
g++ --version
|
g++ --version
|
||||||
cd tests/
|
cd tests/
|
||||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_serialization.cpp -o check_serialization
|
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_DISALLOW_HETEROGENEOUS_ARRAYS -I../ check_serialization.cpp -o check_serialization
|
||||||
git clone https://github.com/BurntSushi/toml-test.git
|
git clone https://github.com/BurntSushi/toml-test.git
|
||||||
cp check_serialization toml-test/tests/valid
|
cp check_serialization toml-test/tests/valid
|
||||||
cd toml-test/tests/valid
|
cd toml-test/tests/valid
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
g++ --version
|
g++ --version
|
||||||
cd tests/
|
cd tests/
|
||||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check.cpp -o check
|
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_DISALLOW_HETEROGENEOUS_ARRAYS -I../ check.cpp -o check
|
||||||
git clone https://github.com/BurntSushi/toml-test.git
|
git clone https://github.com/BurntSushi/toml-test.git
|
||||||
cp check toml-test/tests/invalid
|
cp check toml-test/tests/invalid
|
||||||
cp check toml-test/tests/valid
|
cp check toml-test/tests/valid
|
||||||
|
|||||||
105
.github/workflows/main.yml
vendored
Normal file
105
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
name: build
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-linux-gcc:
|
||||||
|
runs-on: Ubuntu-18.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
# g++-4.8 and 4.9 are tested on Travis.CI.
|
||||||
|
compiler: ['g++-9', 'g++-8', 'g++-7', 'g++-6', 'g++-5']
|
||||||
|
standard: ['11', '14', '17']
|
||||||
|
exclude:
|
||||||
|
- {compiler: 'g++-5', standard: '17'}
|
||||||
|
- {compiler: 'g++-6', standard: '17'}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
sudo apt-add-repository ppa:mhier/libboost-latest
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install boost1.70
|
||||||
|
if [[ "${{ matrix.compiler }}" == "g++-6" || "${{ matrix.compiler }}" == "g++-5" ]] ; then
|
||||||
|
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install ${{ matrix.compiler }}
|
||||||
|
fi
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake .. -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }}
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd build && cmake --build .
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd build && ctest --output-on-failure
|
||||||
|
build-linux-clang:
|
||||||
|
runs-on: Ubuntu-18.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler: ['10', '9', '8', '7', '6.0', '5.0', '4.0', '3.9']
|
||||||
|
standard: ['11', '14', '17']
|
||||||
|
exclude:
|
||||||
|
- {compiler: '3.9', standard: '17'}
|
||||||
|
- {compiler: '4.0', standard: '17'}
|
||||||
|
- {compiler: '5.0', standard: '17'}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
sudo apt-add-repository ppa:mhier/libboost-latest
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install boost1.70
|
||||||
|
if [[ "${{ matrix.compiler }}" != "6" && "${{ matrix.compiler }}" != "8" && "${{ matrix.compiler }}" != "9" ]] ; then
|
||||||
|
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install clang-${{ matrix.compiler }}
|
||||||
|
fi
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake .. -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }}
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd build && cmake --build .
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd build && ctest --output-on-failure
|
||||||
|
build-windows-msvc:
|
||||||
|
runs-on: windows-2019
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
standard: ['11', '14', '17']
|
||||||
|
config: ['Release', 'Debug']
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
- name: Configure
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ../ -G "NMake Makefiles" -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DBoost_ADDITIONAL_VERSIONS=1.72.0 -DBoost_USE_MULTITHREADED=ON -DBoost_ARCHITECTURE=-x64 -DBoost_NO_BOOST_CMAKE=ON -DBOOST_ROOT=%BOOST_ROOT_1_72_0%
|
||||||
|
- name: Build
|
||||||
|
working-directory: ./build
|
||||||
|
run: |
|
||||||
|
cmake --build . --config "${{ matrix.config }}"
|
||||||
|
- name: Test
|
||||||
|
working-directory: ./build
|
||||||
|
run: |
|
||||||
|
file --mime-encoding tests/toml/tests/example.toml
|
||||||
|
file --mime-encoding tests/toml/tests/fruit.toml
|
||||||
|
file --mime-encoding tests/toml/tests/hard_example.toml
|
||||||
|
file --mime-encoding tests/toml/tests/hard_example_unicode.toml
|
||||||
|
ctest --build-config "${{ matrix.config }}" --output-on-failure
|
||||||
48
.travis.yml
48
.travis.yml
@@ -2,6 +2,30 @@ dist: trusty
|
|||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
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
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
@@ -269,16 +293,6 @@ matrix:
|
|||||||
- os: osx
|
- os: osx
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: CXX_STANDARD=11
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/Library/Caches/Homebrew
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
update: true
|
|
||||||
packages:
|
|
||||||
- cmake
|
|
||||||
- boost
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
@@ -288,6 +302,10 @@ script:
|
|||||||
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
||||||
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
||||||
fi
|
fi
|
||||||
|
- |
|
||||||
|
if [[ "${CXX_STANDARD}" == "" ]]; then
|
||||||
|
export CXX_STANDARD="11"
|
||||||
|
fi
|
||||||
- |
|
- |
|
||||||
if [[ "${TOML_HEAD}" != "ON" ]]; then
|
if [[ "${TOML_HEAD}" != "ON" ]]; then
|
||||||
export TOML_HEAD="OFF"
|
export TOML_HEAD="OFF"
|
||||||
@@ -306,14 +324,8 @@ script:
|
|||||||
- cmake --version
|
- cmake --version
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd build
|
- cd build
|
||||||
- git clone https://github.com/toml-lang/toml.git
|
- echo "COMPILER = ${COMPILER}"
|
||||||
|
- echo "CXX_STANDARD = ${CXX_STANDARD}"
|
||||||
- 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} ..
|
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} -Dtoml11_TEST_WITH_ASAN=${WITH_ASAN} -Dtoml11_TEST_WITH_UBSAN=${WITH_UBSAN} ..
|
||||||
- make
|
- make
|
||||||
- ctest --output-on-failure
|
- ctest --output-on-failure
|
||||||
|
|
||||||
# https://stackoverflow.com/a/53331571
|
|
||||||
before_cache:
|
|
||||||
- |
|
|
||||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
|
||||||
brew cleanup
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 3.1)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
project(toml11)
|
project(toml11 VERSION 3.5.0)
|
||||||
|
|
||||||
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_BUILD_TEST "Build toml tests" ON)
|
||||||
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
|
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
|
||||||
@@ -16,11 +9,9 @@ option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF)
|
|||||||
|
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
|
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_STANDARD 11 CACHE STRING "The C++ standard whose features are requested to build all targets.")
|
||||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Boolean describing whether the value of CXX_STANDARD is a requirement.")
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Boolean specifying whether compiler specific extensions are requested.")
|
||||||
endif()
|
|
||||||
set(CXX_STANDARD_REQUIRED ON)
|
|
||||||
else()
|
else()
|
||||||
# Manually check for C++11 compiler flag.
|
# Manually check for C++11 compiler flag.
|
||||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||||
|
|||||||
123
README.md
123
README.md
@@ -1,6 +1,7 @@
|
|||||||
toml11
|
toml11
|
||||||
======
|
======
|
||||||
|
|
||||||
|
[](https://github.com/ToruNiina/toml11/actions)
|
||||||
[](https://travis-ci.org/ToruNiina/toml11)
|
[](https://travis-ci.org/ToruNiina/toml11)
|
||||||
[](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master)
|
[](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master)
|
||||||
[](https://circleci.com/gh/ToruNiina/toml11/tree/master)
|
[](https://circleci.com/gh/ToruNiina/toml11/tree/master)
|
||||||
@@ -8,16 +9,16 @@ toml11
|
|||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://doi.org/10.5281/zenodo.1209136)
|
[](https://doi.org/10.5281/zenodo.1209136)
|
||||||
|
|
||||||
toml11 is a C++11 header-only toml parser/encoder depending only on C++ standard library.
|
toml11 is a C++11 (or later) header-only toml parser/encoder depending only on C++ standard library.
|
||||||
|
|
||||||
compatible to the latest version of
|
- It is compatible to the latest version of [TOML v1.0.0-rc.1](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v1.0.0-rc.1.md).
|
||||||
[TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md)
|
- 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).
|
||||||
after version 2.0.0.
|
- 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 passes [the language agnostic test suite for TOML parsers by BurntSushi](https://github.com/BurntSushi/toml-test).
|
- It optionally preserves comments without any overhead.
|
||||||
Not only the test suite itself, a TOML reader/encoder also runs on [CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
- It has configurable serializer that supports comments, inline tables, literal strings and multiline strings.
|
||||||
You can see the error messages about invalid files and serialization results of valid files at
|
- It supports user-defined type conversion from/into toml values.
|
||||||
[CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
- It correctly handles UTF-8 sequences, with or without BOM, both on posix and Windows.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
@@ -27,15 +28,25 @@ You can see the error messages about invalid files and serialization results of
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
const auto data = toml::parse("example.toml");
|
auto data = toml::parse("example.toml");
|
||||||
|
|
||||||
// title = "an example toml file"
|
// find a value with the specified type from a table
|
||||||
std::string title = toml::find<std::string>(data, "title");
|
std::string title = toml::find<std::string>(data, "title");
|
||||||
std::cout << "the title is " << title << std::endl;
|
|
||||||
|
|
||||||
// nums = [1, 2, 3, 4, 5]
|
// convert the whole array into any container automatically
|
||||||
std::vector<int> nums = toml::find<std::vector<int>>(data, "nums");
|
std::vector<int> nums = toml::find<std::vector<int>>(data, "nums");
|
||||||
std::cout << "the length of `nums` is" << nums.size() << std::endl;
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -109,6 +120,9 @@ const std::string fname("sample.toml");
|
|||||||
const toml::value data = toml::parse(fname);
|
const toml::value data = toml::parse(fname);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
As required by the TOML specification, the top-level value is always a table.
|
||||||
|
You can find a value inside it, cast it into a table explicitly, and insert it as a value into other `toml::value`.
|
||||||
|
|
||||||
If it encounters an error while opening a file, it will throw `std::runtime_error`.
|
If it encounters an error while opening a file, it will throw `std::runtime_error`.
|
||||||
|
|
||||||
You can also pass a `std::istream` to the `toml::parse` function.
|
You can also pass a `std::istream` to the `toml::parse` function.
|
||||||
@@ -256,11 +270,11 @@ shape = "round"
|
|||||||
``` cpp
|
``` cpp
|
||||||
const auto data = toml::parse("fruit.toml");
|
const auto data = toml::parse("fruit.toml");
|
||||||
const auto& fruit = toml::find(data, "fruit");
|
const auto& fruit = toml::find(data, "fruit");
|
||||||
const auto name = toml::find<std::string>(fruit, "apple");
|
const auto name = toml::find<std::string>(fruit, "name");
|
||||||
|
|
||||||
const auto& physical = toml::find(fruit, "physical");
|
const auto& physical = toml::find(fruit, "physical");
|
||||||
const auto color = toml::find<std::string>(fruit, "color");
|
const auto color = toml::find<std::string>(physical, "color");
|
||||||
const auto shape = toml::find<std::string>(fruit, "shape");
|
const auto shape = toml::find<std::string>(physical, "shape");
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, variable `fruit` is a `toml::value` and can be used as the first argument
|
Here, variable `fruit` is a `toml::value` and can be used as the first argument
|
||||||
@@ -452,6 +466,24 @@ if(answer.is_integer() && answer.as_integer(std::nothrow) == 42)
|
|||||||
|
|
||||||
If `std::nothrow` is passed, the functions are marked as noexcept.
|
If `std::nothrow` is passed, the functions are marked as noexcept.
|
||||||
|
|
||||||
|
By casting a `toml::value` into an array or a table, you can iterate over the
|
||||||
|
elements.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const auto data = toml::parse("example.toml");
|
||||||
|
std::cout << "keys in the top-level table are the following: \n";
|
||||||
|
for(const auto& [k, v] : data.as_table())
|
||||||
|
{
|
||||||
|
std::cout << k << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& fruits = toml::find(data, "fruits");
|
||||||
|
for(const auto& v : fruits.as_array())
|
||||||
|
{
|
||||||
|
std::cout << toml::find<std::string>(v, "name") << '\n';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The full list of the functions is below.
|
The full list of the functions is below.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -1413,7 +1445,7 @@ const toml::source_location loc = v.location();
|
|||||||
|
|
||||||
## Exceptions
|
## Exceptions
|
||||||
|
|
||||||
All the exceptions thrown by toml11 inherits `toml::exception` that inherits
|
The following `exception` classes inherits `toml::exception` that inherits
|
||||||
`std::exception`.
|
`std::exception`.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -1440,6 +1472,16 @@ struct exception : public std::exception
|
|||||||
|
|
||||||
It represents where the error occurs.
|
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
|
## Colorize Error Messages
|
||||||
|
|
||||||
By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from
|
By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from
|
||||||
@@ -1631,13 +1673,8 @@ not capable of representing a Local Time independent from a specific day.
|
|||||||
|
|
||||||
## Unreleased TOML features
|
## Unreleased TOML features
|
||||||
|
|
||||||
There are some unreleased features in toml-lang/toml:master.
|
Since TOML v1.0.0-rc.1 has been released, those features are now activated by
|
||||||
Currently, the following features are available after defining
|
default. We no longer need to define `TOML11_USE_UNRELEASED_FEATURES`.
|
||||||
`TOML11_USE_UNRELEASED_TOML_FEATURES` macro flag.
|
|
||||||
|
|
||||||
To use those features, `#define` `TOML11_USE_UNRELEASED_TOML_FEATURES` before
|
|
||||||
including `toml.hpp` or pass `-DTOML11_USE_UNRELEASED_TOML_FEATURES` to your
|
|
||||||
compiler.
|
|
||||||
|
|
||||||
- Leading zeroes in exponent parts of floats are permitted.
|
- Leading zeroes in exponent parts of floats are permitted.
|
||||||
- e.g. `1.0e+01`, `5e+05`
|
- e.g. `1.0e+01`, `5e+05`
|
||||||
@@ -1647,10 +1684,10 @@ compiler.
|
|||||||
- Allow heterogeneous arrays
|
- Allow heterogeneous arrays
|
||||||
- [toml-lang/toml/PR/676](https://github.com/toml-lang/toml/pull/676)
|
- [toml-lang/toml/PR/676](https://github.com/toml-lang/toml/pull/676)
|
||||||
|
|
||||||
### Note about heterogeneous arrays
|
## Note about heterogeneous arrays
|
||||||
|
|
||||||
Although `toml::parse` allows heterogeneous arrays, constructor of `toml::value`
|
Although `toml::parse` allows heterogeneous arrays, constructor of `toml::value`
|
||||||
does not.
|
does not. Here the reason is explained.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// this won't be compiled
|
// this won't be compiled
|
||||||
@@ -1659,8 +1696,10 @@ toml::value v{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
There is a workaround for this issue. By explicitly converting values into
|
There is a workaround for this. By explicitly converting values into
|
||||||
`toml::value`, you can initialize `toml::value` with a heterogeneous array.
|
`toml::value`, you can initialize `toml::value` with a heterogeneous array.
|
||||||
|
Also, you can first initialize a `toml::value` with an array and then
|
||||||
|
`push_back` into it.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// OK!
|
// OK!
|
||||||
@@ -1668,6 +1707,17 @@ toml::value v{
|
|||||||
toml::value("foo"), toml::value(3.14), toml::value(42),
|
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||||
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OK!
|
||||||
|
toml::value v(toml::array{});
|
||||||
|
v.push_back("foo");
|
||||||
|
v.push_back(3.14);
|
||||||
|
|
||||||
|
// OK!
|
||||||
|
toml::array a;
|
||||||
|
a.push_back("foo");
|
||||||
|
a.push_back(3.14);
|
||||||
|
toml::value v(std::move(a));
|
||||||
```
|
```
|
||||||
|
|
||||||
The reason why the first example is not allowed is the following.
|
The reason why the first example is not allowed is the following.
|
||||||
@@ -1696,15 +1746,14 @@ This means that the above C++ code makes constructor's overload resolution
|
|||||||
ambiguous. So a constructor that allows both "table as an initializer-list" and
|
ambiguous. So a constructor that allows both "table as an initializer-list" and
|
||||||
"heterogeneous array as an initializer-list" cannot be implemented.
|
"heterogeneous array as an initializer-list" cannot be implemented.
|
||||||
|
|
||||||
Thus, although it is painful, you need to explicitly cast values into
|
Thus, although it is painful, we need to explicitly cast values into
|
||||||
`toml::value` when you initialize heterogeneous array in C++ code.
|
`toml::value` when you initialize heterogeneous array in a C++ code.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// You need to do this when you want to initialize hetero array.
|
|
||||||
toml::value v{
|
toml::value v{
|
||||||
toml::value("foo"), toml::value(3.14), toml::value(42),
|
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||||
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## Breaking Changes from v2
|
## Breaking Changes from v2
|
||||||
@@ -1743,13 +1792,12 @@ Such a big change will not happen in the coming years.
|
|||||||
|
|
||||||
## Running Tests
|
## Running Tests
|
||||||
|
|
||||||
To run test codes, you need to clone toml-lang/toml repository under `build/` directory
|
After cloning this repository, run the following command (thank you @jwillikers
|
||||||
because some of the test codes read a file in the repository.
|
for automating test set fetching!).
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
$ cd build
|
$ cd build
|
||||||
$ git clone https://github.com/toml-lang/toml.git
|
|
||||||
$ cmake ..
|
$ cmake ..
|
||||||
$ make
|
$ make
|
||||||
$ make test
|
$ make test
|
||||||
@@ -1783,6 +1831,11 @@ I appreciate the help of the contributors who introduced the great feature to th
|
|||||||
- Suppress warnings in Debug mode
|
- Suppress warnings in Debug mode
|
||||||
- OGAWA Kenichi (@kenichiice)
|
- OGAWA Kenichi (@kenichiice)
|
||||||
- Suppress warnings on intel compiler
|
- 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
|
## Licensing terms
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,9 @@ build_script:
|
|||||||
- cd C:\toml11
|
- cd C:\toml11
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd 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 -G"%generator%" -DBOOST_ROOT=C:/Libraries/boost_1_69_0 ..
|
||||||
- cmake --build . --config "%configuration%"
|
- cmake --build . --config "%configuration%"
|
||||||
|
- file --mime-encoding tests/toml/tests/hard_example_unicode.toml
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- ctest --build-config "%configuration%" --timeout 300 --output-on-failure
|
- ctest --build-config "%configuration%" --timeout 300 --output-on-failure
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
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
|
set(TEST_NAMES
|
||||||
test_datetime
|
test_datetime
|
||||||
test_string
|
test_string
|
||||||
@@ -48,6 +57,8 @@ CHECK_CXX_COMPILER_FLAG("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BR
|
|||||||
CHECK_CXX_COMPILER_FLAG("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
|
CHECK_CXX_COMPILER_FLAG("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
|
||||||
CHECK_CXX_COMPILER_FLAG("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
|
CHECK_CXX_COMPILER_FLAG("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
|
||||||
CHECK_CXX_COMPILER_FLAG("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
|
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)
|
if(COMPILER_SUPPORTS_WALL)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||||
@@ -82,6 +93,12 @@ endif()
|
|||||||
if(COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
|
if(COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
|
||||||
endif()
|
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
|
option(TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||||
"use features in toml-lang/toml master while testing" OFF)
|
"use features in toml-lang/toml master while testing" OFF)
|
||||||
@@ -150,7 +167,7 @@ foreach(TEST_NAME ${TEST_NAMES})
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
# Set the PATH to be able to find Boost DLL
|
# Set the PATH to be able to find Boost DLL
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
@@ -166,3 +183,9 @@ add_executable(test_multiple_translation_unit
|
|||||||
test_multiple_translation_unit_1.cpp
|
test_multiple_translation_unit_1.cpp
|
||||||
test_multiple_translation_unit_2.cpp)
|
test_multiple_translation_unit_2.cpp)
|
||||||
target_link_libraries(test_multiple_translation_unit toml11::toml11)
|
target_link_libraries(test_multiple_translation_unit toml11::toml11)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
add_executable(test_windows test_windows.cpp)
|
||||||
|
target_link_libraries(test_windows toml11::toml11)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -84,9 +84,7 @@ struct json_serializer
|
|||||||
{
|
{
|
||||||
if(!is_first) {std::cout << ", ";}
|
if(!is_first) {std::cout << ", ";}
|
||||||
is_first = false;
|
is_first = false;
|
||||||
std::cout << toml::format(toml::value(elem.first),
|
std::cout << this->format_key(elem.first) << ':';
|
||||||
std::numeric_limits<std::size_t>::max());
|
|
||||||
std::cout << ':';
|
|
||||||
toml::visit(*this, elem.second);
|
toml::visit(*this, elem.second);
|
||||||
}
|
}
|
||||||
std::cout << '}';
|
std::cout << '}';
|
||||||
@@ -112,6 +110,12 @@ struct json_serializer
|
|||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string format_key(const std::string& s) const
|
||||||
|
{
|
||||||
|
const auto quote("\"");
|
||||||
|
return quote + escape_string(s) + quote;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|||||||
@@ -80,13 +80,13 @@ BOOST_AUTO_TEST_CASE(test_detect_conflicting_value)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
|
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
|
||||||
{
|
{
|
||||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
#ifdef TOML11_DISALLOW_HETEROGENEOUS_ARRAYS
|
||||||
BOOST_TEST_MESSAGE("heterogeneous array will be allowed in the next release");
|
|
||||||
#else
|
|
||||||
std::istringstream stream(std::string(
|
std::istringstream stream(std::string(
|
||||||
"a = [1, 1.0]\n"
|
"a = [1, 1.0]\n"
|
||||||
));
|
));
|
||||||
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
||||||
|
#else
|
||||||
|
BOOST_TEST_MESSAGE("After v1.0.0-rc.1, heterogeneous arrays are allowed");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ struct qux
|
|||||||
|
|
||||||
struct foobar
|
struct foobar
|
||||||
{
|
{
|
||||||
foobar() = default; // later we use std::vector<foobar>, default ctor is required.
|
|
||||||
|
|
||||||
// via constructor
|
// via constructor
|
||||||
explicit foobar(const toml::value& v)
|
explicit foobar(const toml::value& v)
|
||||||
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
|
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
|
||||||
@@ -137,8 +135,6 @@ struct qux
|
|||||||
|
|
||||||
struct foobar
|
struct foobar
|
||||||
{
|
{
|
||||||
foobar() = default; // later we use std::vector<foobar>, default ctor is required.
|
|
||||||
|
|
||||||
template<typename C, template<typename ...> class M, template<typename ...> class A>
|
template<typename C, template<typename ...> class M, template<typename ...> class A>
|
||||||
explicit foobar(const toml::basic_value<C, M, A>& v)
|
explicit foobar(const toml::basic_value<C, M, A>& v)
|
||||||
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
|
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
|
||||||
@@ -488,5 +484,64 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
|||||||
BOOST_TEST(foobars.at(2).b == "quux");
|
BOOST_TEST(foobars.at(2).b == "quux");
|
||||||
BOOST_TEST(foobars.at(3).b == "foobar");
|
BOOST_TEST(foobars.at(3).b == "foobar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// via constructor
|
||||||
|
{
|
||||||
|
const toml::value v{
|
||||||
|
{"0", toml::table{{"a", 42}, {"b", "baz"}}},
|
||||||
|
{"1", toml::table{{"a", 43}, {"b", "qux"}}},
|
||||||
|
{"2", toml::table{{"a", 44}, {"b", "quux"}}},
|
||||||
|
{"3", toml::table{{"a", 45}, {"b", "foobar"}}}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto foobars = toml::get<std::map<std::string, extlib::foobar>>(v);
|
||||||
|
BOOST_TEST(foobars.size() == 4ul);
|
||||||
|
BOOST_TEST(foobars.at("0").a == 42);
|
||||||
|
BOOST_TEST(foobars.at("1").a == 43);
|
||||||
|
BOOST_TEST(foobars.at("2").a == 44);
|
||||||
|
BOOST_TEST(foobars.at("3").a == 45);
|
||||||
|
|
||||||
|
BOOST_TEST(foobars.at("0").b == "baz");
|
||||||
|
BOOST_TEST(foobars.at("1").b == "qux");
|
||||||
|
BOOST_TEST(foobars.at("2").b == "quux");
|
||||||
|
BOOST_TEST(foobars.at("3").b == "foobar");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto foobars = toml::get<std::map<std::string, extlib2::foobar>>(v);
|
||||||
|
BOOST_TEST(foobars.size() == 4ul);
|
||||||
|
BOOST_TEST(foobars.at("0").a == 42);
|
||||||
|
BOOST_TEST(foobars.at("1").a == 43);
|
||||||
|
BOOST_TEST(foobars.at("2").a == 44);
|
||||||
|
BOOST_TEST(foobars.at("3").a == 45);
|
||||||
|
|
||||||
|
BOOST_TEST(foobars.at("0").b == "baz");
|
||||||
|
BOOST_TEST(foobars.at("1").b == "qux");
|
||||||
|
BOOST_TEST(foobars.at("2").b == "quux");
|
||||||
|
BOOST_TEST(foobars.at("3").b == "foobar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||||
|
v{
|
||||||
|
{"0", toml::table{{"a", 42}, {"b", "baz"}}},
|
||||||
|
{"1", toml::table{{"a", 43}, {"b", "qux"}}},
|
||||||
|
{"2", toml::table{{"a", 44}, {"b", "quux"}}},
|
||||||
|
{"3", toml::table{{"a", 45}, {"b", "foobar"}}}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto foobars = toml::get<std::map<std::string, extlib::foobar>>(v);
|
||||||
|
BOOST_TEST(foobars.size() == 4ul);
|
||||||
|
BOOST_TEST(foobars.at("0").a == 42);
|
||||||
|
BOOST_TEST(foobars.at("1").a == 43);
|
||||||
|
BOOST_TEST(foobars.at("2").a == 44);
|
||||||
|
BOOST_TEST(foobars.at("3").a == 45);
|
||||||
|
|
||||||
|
BOOST_TEST(foobars.at("0").b == "baz");
|
||||||
|
BOOST_TEST(foobars.at("1").b == "qux");
|
||||||
|
BOOST_TEST(foobars.at("2").b == "quux");
|
||||||
|
BOOST_TEST(foobars.at("3").b == "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,22 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
|||||||
TOML11_TEST_LEX_ACCEPT(lex_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 \"\"\"",
|
||||||
"\"\"\"\\\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)
|
BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||||
@@ -83,4 +99,16 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
|
|||||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
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'''",
|
||||||
"'''\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.''''");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(test_example)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_example_stream)
|
BOOST_AUTO_TEST_CASE(test_example_stream)
|
||||||
{
|
{
|
||||||
std::ifstream ifs("toml/tests/example.toml");
|
std::ifstream ifs("toml/tests/example.toml", std::ios::binary);
|
||||||
const auto data = toml::parse(ifs);
|
const auto data = toml::parse(ifs);
|
||||||
|
|
||||||
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
|
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
|
|||||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||||
"\" And when \\\"'s are in the along with # \\\"\"",
|
"\" And when \\\"'s are in the along with # \\\"\"",
|
||||||
string(" And when \"'s are in the along with # \"", string_t::basic));
|
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)
|
BOOST_AUTO_TEST_CASE(test_basic_string_value)
|
||||||
@@ -94,6 +97,9 @@ 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>,
|
||||||
"\" And when \\\"'s are in the along with # \\\"\"",
|
"\" And when \\\"'s are in the along with # \\\"\"",
|
||||||
value(" And when \"'s are in the along with # \"", string_t::basic));
|
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)
|
BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
||||||
@@ -104,6 +110,18 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
|||||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
TOML11_TEST_PARSE_EQUAL(parse_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 \"\"\"",
|
||||||
string("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
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)
|
BOOST_AUTO_TEST_CASE(test_ml_basic_string_value)
|
||||||
@@ -114,6 +132,19 @@ 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>,
|
||||||
"\"\"\"\\\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 \"\"\"",
|
||||||
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
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)
|
BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||||
@@ -156,6 +187,15 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
|
|||||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
TOML11_TEST_PARSE_EQUAL(parse_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'''",
|
||||||
string("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
|
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)
|
BOOST_AUTO_TEST_CASE(test_ml_literal_string_value)
|
||||||
@@ -166,6 +206,15 @@ 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>,
|
||||||
"'''\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'''",
|
||||||
value("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
|
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)
|
BOOST_AUTO_TEST_CASE(test_unicode_escape_sequence)
|
||||||
|
|||||||
@@ -9,27 +9,24 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_resize)
|
BOOST_AUTO_TEST_CASE(test_try_reserve)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
typedef std::vector<int> resizable_type;
|
// since BOOST_TEST is a macro, it cannot handle commas correctly.
|
||||||
typedef std::array<int,1> non_resizable_type;
|
// When toml::detail::has_reserve_method<std::array<int, 1>>::value
|
||||||
BOOST_TEST(toml::detail::has_resize_method<resizable_type>::value);
|
// is passed to a macro, C preprocessor considers
|
||||||
BOOST_TEST(!toml::detail::has_resize_method<non_resizable_type>::value);
|
// toml::detail::has_reserve_method<std::array<int as the first argument
|
||||||
|
// and 1>>::value as the second argument. We need an alias to avoid
|
||||||
|
// this problem.
|
||||||
|
using reservable_type = std::vector<int> ;
|
||||||
|
using nonreservable_type = std::array<int, 1>;
|
||||||
|
BOOST_TEST( toml::detail::has_reserve_method<reservable_type >::value);
|
||||||
|
BOOST_TEST(!toml::detail::has_reserve_method<nonreservable_type>::value);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::vector<int> v;
|
std::vector<int> v;
|
||||||
toml::resize(v, 10);
|
toml::try_reserve(v, 100);
|
||||||
BOOST_TEST(v.size() == 10u);
|
BOOST_TEST(v.capacity() == 100u);
|
||||||
}
|
|
||||||
{
|
|
||||||
std::array<int, 15> a;
|
|
||||||
toml::resize(a, 10);
|
|
||||||
BOOST_TEST(a.size() == 15u);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::array<int, 15> a;
|
|
||||||
BOOST_CHECK_THROW(toml::resize(a, 20), std::invalid_argument);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
tests/test_windows.cpp
Normal file
12
tests/test_windows.cpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <toml.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using namespace toml::literals::toml_literals;
|
||||||
|
const auto data = u8R"(windows = "defines min and max as a macro")"_toml;
|
||||||
|
|
||||||
|
std::cout << toml::find<std::string>(data, "windows") << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
4
toml.hpp
4
toml.hpp
@@ -33,6 +33,10 @@
|
|||||||
# error "toml11 requires C++11 or later."
|
# error "toml11 requires C++11 or later."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TOML11_VERSION_MAJOR 3
|
||||||
|
#define TOML11_VERSION_MINOR 5
|
||||||
|
#define TOML11_VERSION_PATCH 0
|
||||||
|
|
||||||
#include "toml/parser.hpp"
|
#include "toml/parser.hpp"
|
||||||
#include "toml/literal.hpp"
|
#include "toml/literal.hpp"
|
||||||
#include "toml/serializer.hpp"
|
#include "toml/serializer.hpp"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef TOML11_COLOR_HPP
|
#ifndef TOML11_COLOR_HPP
|
||||||
#define TOML11_COLOR_HPP
|
#define TOML11_COLOR_HPP
|
||||||
#include <ostream>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
#ifdef TOML11_COLORIZE_ERROR_MESSAGE
|
#ifdef TOML11_COLORIZE_ERROR_MESSAGE
|
||||||
#define TOML11_ERROR_MESSAGE_COLORIZED true
|
#define TOML11_ERROR_MESSAGE_COLORIZED true
|
||||||
|
|||||||
@@ -2,18 +2,20 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_COMBINATOR_HPP
|
#ifndef TOML11_COMBINATOR_HPP
|
||||||
#define TOML11_COMBINATOR_HPP
|
#define TOML11_COMBINATOR_HPP
|
||||||
#include "traits.hpp"
|
|
||||||
#include "result.hpp"
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "region.hpp"
|
|
||||||
#include <type_traits>
|
|
||||||
#include <iterator>
|
|
||||||
#include <limits>
|
|
||||||
#include <array>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iterator>
|
||||||
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "region.hpp"
|
||||||
|
#include "result.hpp"
|
||||||
|
#include "traits.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
// they scans characters and returns region if it matches to the condition.
|
// they scans characters and returns region if it matches to the condition.
|
||||||
// when they fail, it does not change the location.
|
// when they fail, it does not change the location.
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_COMMENTS_HPP
|
#ifndef TOML11_COMMENTS_HPP
|
||||||
#define TOML11_COMMENTS_HPP
|
#define TOML11_COMMENTS_HPP
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <iterator>
|
||||||
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <iterator>
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
|
// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
|
||||||
// Those two are a container that have the same interface as `std::vector<std::string>`
|
// Those two are a container that have the same interface as `std::vector<std::string>`
|
||||||
@@ -81,6 +81,54 @@ struct preserve_comments
|
|||||||
void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}
|
void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}
|
||||||
void assign(size_type n, const std::string& val) {comments.assign(n, val);}
|
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)
|
iterator insert(const_iterator p, const std::string& x)
|
||||||
{
|
{
|
||||||
return comments.insert(p, x);
|
return comments.insert(p, x);
|
||||||
@@ -114,6 +162,7 @@ struct preserve_comments
|
|||||||
{
|
{
|
||||||
return comments.erase(first, last);
|
return comments.erase(first, last);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void swap(preserve_comments& other) {comments.swap(other.comments);}
|
void swap(preserve_comments& other) {comments.swap(other.comments);}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,16 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_DATETIME_HPP
|
#ifndef TOML11_DATETIME_HPP
|
||||||
#define TOML11_DATETIME_HPP
|
#define TOML11_DATETIME_HPP
|
||||||
#include <chrono>
|
|
||||||
#include <tuple>
|
|
||||||
#include <array>
|
|
||||||
#include <ostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <ostream>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ namespace toml
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
// TODO: find more sophisticated way to handle this
|
// TODO: find more sophisticated way to handle this
|
||||||
#if _POSIX_C_SOURCE >= 1 || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
std::tm dst;
|
std::tm dst;
|
||||||
@@ -35,7 +36,7 @@ inline std::tm gmtime_s(const std::time_t* src)
|
|||||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
#elif _MSC_VER
|
#elif defined(_MSC_VER)
|
||||||
inline std::tm localtime_s(const std::time_t* src)
|
inline std::tm localtime_s(const std::time_t* src)
|
||||||
{
|
{
|
||||||
std::tm dst;
|
std::tm dst;
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_EXCEPTION_HPP
|
#ifndef TOML11_EXCEPTION_HPP
|
||||||
#define TOML11_EXCEPTION_HPP
|
#define TOML11_EXCEPTION_HPP
|
||||||
#include "source_location.hpp"
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "source_location.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
90
toml/get.hpp
90
toml/get.hpp
@@ -2,10 +2,11 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_GET_HPP
|
#ifndef TOML11_GET_HPP
|
||||||
#define TOML11_GET_HPP
|
#define TOML11_GET_HPP
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "from.hpp"
|
#include "from.hpp"
|
||||||
#include "result.hpp"
|
#include "result.hpp"
|
||||||
#include "value.hpp"
|
#include "value.hpp"
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
@@ -198,23 +199,23 @@ get(const basic_value<C, M, V>& v)
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
// forward declaration to use this recursively. ignore this and go ahead.
|
// forward declaration to use this recursively. ignore this and go ahead.
|
||||||
|
|
||||||
// array-like type with resize(N) method
|
// array-like type with push_back(value) method
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::is_container<T>, // T is container
|
detail::is_container<T>, // T is a container
|
||||||
detail::has_resize_method<T>, // T::resize(N) works
|
detail::has_push_back_method<T>, // T::push_back(value) works
|
||||||
detail::negation< // but not toml::array
|
detail::negation< // but not toml::array
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||||
>::value, T>
|
>::value, T>
|
||||||
get(const basic_value<C, M, V>&);
|
get(const basic_value<C, M, V>&);
|
||||||
|
|
||||||
// array-like type with resize(N) method
|
// array-like type without push_back(value) method
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::is_container<T>, // T is container
|
detail::is_container<T>, // T is a container
|
||||||
detail::negation<detail::has_resize_method<T>>, // no T::resize() exists
|
detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
|
||||||
detail::negation< // not toml::array
|
detail::negation< // not toml::array
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||||
>::value, T>
|
>::value, T>
|
||||||
@@ -274,31 +275,54 @@ get(const basic_value<C, M, V>&);
|
|||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::is_container<T>, // T is container
|
detail::is_container<T>, // T is a container
|
||||||
detail::has_resize_method<T>, // T::resize(N) works
|
detail::has_push_back_method<T>, // container.push_back(elem) works
|
||||||
detail::negation< // but not toml::array
|
detail::negation< // but not toml::array
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||||
>::value, T>
|
>::value, T>
|
||||||
get(const basic_value<C, M, V>& v)
|
get(const basic_value<C, M, V>& v)
|
||||||
{
|
{
|
||||||
using value_type = typename T::value_type;
|
using value_type = typename T::value_type;
|
||||||
const auto& ar = v.as_array();
|
const auto& ary = v.as_array();
|
||||||
|
|
||||||
T container;
|
T container;
|
||||||
container.resize(ar.size());
|
try_reserve(container, ary.size());
|
||||||
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
|
||||||
[](const value& x){return ::toml::get<value_type>(x);});
|
for(const auto& elem : ary)
|
||||||
|
{
|
||||||
|
container.push_back(get<value_type>(elem));
|
||||||
|
}
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// array-like types; but does not have resize(); most likely std::array.
|
// std::forward_list does not have push_back, insert, or emplace.
|
||||||
|
// It has insert_after, emplace_after, push_front.
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::is_std_forward_list<T>::value, T>
|
||||||
|
get(const basic_value<C, M, V>& v)
|
||||||
|
{
|
||||||
|
using value_type = typename T::value_type;
|
||||||
|
T container;
|
||||||
|
for(const auto& elem : v.as_array())
|
||||||
|
{
|
||||||
|
container.push_front(get<value_type>(elem));
|
||||||
|
}
|
||||||
|
container.reverse();
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// array-like types, without push_back(). most likely [std|boost]::array.
|
||||||
|
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
detail::enable_if_t<detail::conjunction<
|
detail::enable_if_t<detail::conjunction<
|
||||||
detail::is_container<T>, // T is container
|
detail::is_container<T>, // T is a container
|
||||||
detail::negation<detail::has_resize_method<T>>, // no T::resize() exists
|
detail::negation<detail::has_push_back_method<T>>, // w/o push_back
|
||||||
detail::negation< // but not toml::array
|
detail::negation< // T is not toml::array
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||||
>::value, T>
|
>::value, T>
|
||||||
get(const basic_value<C, M, V>& v)
|
get(const basic_value<C, M, V>& v)
|
||||||
@@ -396,7 +420,7 @@ get(const basic_value<C, M, V>& v)
|
|||||||
T map;
|
T map;
|
||||||
for(const auto& kv : v.as_table())
|
for(const auto& kv : v.as_table())
|
||||||
{
|
{
|
||||||
map[key_type(kv.first)] = ::toml::get<mapped_type>(kv.second);
|
map.emplace(key_type(kv.first), get<mapped_type>(kv.second));
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
@@ -449,10 +473,7 @@ basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
|||||||
const auto& tab = v.as_table();
|
const auto& tab = v.as_table();
|
||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
detail::throw_key_not_found_error(v, ky);
|
||||||
"key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return tab.at(ky);
|
return tab.at(ky);
|
||||||
}
|
}
|
||||||
@@ -463,10 +484,7 @@ basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
|||||||
auto& tab = v.as_table();
|
auto& tab = v.as_table();
|
||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
detail::throw_key_not_found_error(v, ky);
|
||||||
"key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return tab.at(ky);
|
return tab.at(ky);
|
||||||
}
|
}
|
||||||
@@ -477,10 +495,7 @@ 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();
|
typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
|
||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
detail::throw_key_not_found_error(v, ky);
|
||||||
"key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return basic_value<C, M, V>(std::move(tab.at(ky)));
|
return basic_value<C, M, V>(std::move(tab.at(ky)));
|
||||||
}
|
}
|
||||||
@@ -542,10 +557,7 @@ find(const basic_value<C, M, V>& v, const key& ky)
|
|||||||
const auto& tab = v.as_table();
|
const auto& tab = v.as_table();
|
||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
detail::throw_key_not_found_error(v, ky);
|
||||||
"key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return ::toml::get<T>(tab.at(ky));
|
return ::toml::get<T>(tab.at(ky));
|
||||||
}
|
}
|
||||||
@@ -558,10 +570,7 @@ find(basic_value<C, M, V>& v, const key& ky)
|
|||||||
auto& tab = v.as_table();
|
auto& tab = v.as_table();
|
||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
detail::throw_key_not_found_error(v, ky);
|
||||||
"key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return ::toml::get<T>(tab.at(ky));
|
return ::toml::get<T>(tab.at(ky));
|
||||||
}
|
}
|
||||||
@@ -574,10 +583,7 @@ find(basic_value<C, M, V>&& v, const key& ky)
|
|||||||
typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
|
typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
|
||||||
if(tab.count(ky) == 0)
|
if(tab.count(ky) == 0)
|
||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
detail::throw_key_not_found_error(v, ky);
|
||||||
"key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return ::toml::get<T>(std::move(tab.at(ky)));
|
return ::toml::get<T>(std::move(tab.at(ky)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_LEXER_HPP
|
#ifndef TOML11_LEXER_HPP
|
||||||
#define TOML11_LEXER_HPP
|
#define TOML11_LEXER_HPP
|
||||||
#include "combinator.hpp"
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "combinator.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
@@ -69,15 +70,8 @@ using lex_zero_prefixable_int = sequence<lex_digit, repeat<either<lex_digit,
|
|||||||
|
|
||||||
using lex_fractional_part = sequence<character<'.'>, lex_zero_prefixable_int>;
|
using lex_fractional_part = sequence<character<'.'>, lex_zero_prefixable_int>;
|
||||||
|
|
||||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
|
||||||
// use toml-lang/toml HEAD
|
|
||||||
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>,
|
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>,
|
||||||
maybe<lex_sign>, lex_zero_prefixable_int>;
|
maybe<lex_sign>, lex_zero_prefixable_int>;
|
||||||
#else
|
|
||||||
// strictly TOML v0.5.0
|
|
||||||
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>,
|
|
||||||
lex_dec_int>;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using lex_float = either<lex_special_float,
|
using lex_float = either<lex_special_float,
|
||||||
sequence<lex_dec_int, either<lex_exponent_part,
|
sequence<lex_dec_int, either<lex_exponent_part,
|
||||||
@@ -125,17 +119,11 @@ using lex_local_time = lex_partial_time;
|
|||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
using lex_quotation_mark = character<'"'>;
|
using lex_quotation_mark = character<'"'>;
|
||||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
|
||||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab)
|
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab)
|
||||||
in_range<0x0a, 0x1F>, // is allowed
|
in_range<0x0a, 0x1F>, // is allowed
|
||||||
character<0x22>, character<0x5C>,
|
character<0x22>, character<0x5C>,
|
||||||
character<0x7F>>>;
|
character<0x7F>>>;
|
||||||
#else
|
|
||||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x1F>,
|
|
||||||
character<0x22>, character<0x5C>,
|
|
||||||
character<0x7F>>>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
using lex_escape = character<'\\'>;
|
using lex_escape = character<'\\'>;
|
||||||
using lex_escape_unicode_short = sequence<character<'u'>,
|
using lex_escape_unicode_short = sequence<character<'u'>,
|
||||||
repeat<lex_hex_dig, exactly<4>>>;
|
repeat<lex_hex_dig, exactly<4>>>;
|
||||||
@@ -154,19 +142,47 @@ using lex_basic_string = sequence<lex_quotation_mark,
|
|||||||
repeat<lex_basic_char, unlimited>,
|
repeat<lex_basic_char, unlimited>,
|
||||||
lex_quotation_mark>;
|
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.
|
||||||
|
//
|
||||||
using lex_ml_basic_string_delim = repeat<lex_quotation_mark, exactly<3>>;
|
using lex_ml_basic_string_delim = repeat<lex_quotation_mark, exactly<3>>;
|
||||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
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>
|
||||||
|
>;
|
||||||
|
|
||||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09
|
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09
|
||||||
in_range<0x0a, 0x1F>, // is tab
|
in_range<0x0a, 0x1F>, // is tab
|
||||||
character<0x5C>,
|
character<0x5C>, // backslash
|
||||||
character<0x7F>,
|
character<0x7F>, // DEL
|
||||||
lex_ml_basic_string_delim>>;
|
lex_ml_basic_string_delim>>;
|
||||||
#else // TOML v0.5.0
|
|
||||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00,0x1F>,
|
|
||||||
character<0x5C>,
|
|
||||||
character<0x7F>,
|
|
||||||
lex_ml_basic_string_delim>>;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using lex_ml_basic_escaped_newline = sequence<
|
using lex_ml_basic_escaped_newline = sequence<
|
||||||
lex_escape, maybe<lex_ws>, lex_newline,
|
lex_escape, maybe<lex_ws>, lex_newline,
|
||||||
@@ -176,9 +192,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,
|
using lex_ml_basic_body = repeat<either<lex_ml_basic_char, lex_newline,
|
||||||
lex_ml_basic_escaped_newline>,
|
lex_ml_basic_escaped_newline>,
|
||||||
unlimited>;
|
unlimited>;
|
||||||
using lex_ml_basic_string = sequence<lex_ml_basic_string_delim,
|
using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
|
||||||
lex_ml_basic_body,
|
lex_ml_basic_body,
|
||||||
lex_ml_basic_string_delim>;
|
lex_ml_basic_string_close>;
|
||||||
|
|
||||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
|
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||||
in_range<0x10, 0x19>, character<0x27>>>;
|
in_range<0x10, 0x19>, character<0x27>>>;
|
||||||
@@ -187,7 +203,13 @@ using lex_literal_string = sequence<lex_apostrophe,
|
|||||||
repeat<lex_literal_char, unlimited>,
|
repeat<lex_literal_char, unlimited>,
|
||||||
lex_apostrophe>;
|
lex_apostrophe>;
|
||||||
|
|
||||||
|
// the same reason as above.
|
||||||
using lex_ml_literal_string_delim = repeat<lex_apostrophe, exactly<3>>;
|
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>,
|
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||||
in_range<0x10, 0x1F>,
|
in_range<0x10, 0x1F>,
|
||||||
@@ -195,9 +217,9 @@ using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
|||||||
lex_ml_literal_string_delim>>;
|
lex_ml_literal_string_delim>>;
|
||||||
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
|
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
|
||||||
unlimited>;
|
unlimited>;
|
||||||
using lex_ml_literal_string = sequence<lex_ml_literal_string_delim,
|
using lex_ml_literal_string = sequence<lex_ml_literal_string_open,
|
||||||
lex_ml_literal_body,
|
lex_ml_literal_body,
|
||||||
lex_ml_literal_string_delim>;
|
lex_ml_literal_string_close>;
|
||||||
|
|
||||||
using lex_string = either<lex_ml_basic_string, lex_basic_string,
|
using lex_string = either<lex_ml_basic_string, lex_basic_string,
|
||||||
lex_ml_literal_string, lex_literal_string>;
|
lex_ml_literal_string, lex_literal_string>;
|
||||||
|
|||||||
128
toml/parser.hpp
128
toml/parser.hpp
@@ -2,15 +2,23 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_PARSER_HPP
|
#ifndef TOML11_PARSER_HPP
|
||||||
#define TOML11_PARSER_HPP
|
#define TOML11_PARSER_HPP
|
||||||
#include "result.hpp"
|
#include <cstring>
|
||||||
#include "region.hpp"
|
|
||||||
#include "combinator.hpp"
|
|
||||||
#include "lexer.hpp"
|
|
||||||
#include "types.hpp"
|
|
||||||
#include "value.hpp"
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstring>
|
|
||||||
|
#include "combinator.hpp"
|
||||||
|
#include "lexer.hpp"
|
||||||
|
#include "region.hpp"
|
||||||
|
#include "result.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "value.hpp"
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
#if __has_include(<filesystem>)
|
||||||
|
#define TOML11_HAS_STD_FILESYSTEM
|
||||||
|
#include <filesystem>
|
||||||
|
#endif // has_include(<string_view>)
|
||||||
|
#endif // cplusplus >= C++17
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
@@ -375,7 +383,7 @@ parse_ml_basic_string(location<Container>& loc)
|
|||||||
std::string retval;
|
std::string retval;
|
||||||
retval.reserve(token.unwrap().size());
|
retval.reserve(token.unwrap().size());
|
||||||
|
|
||||||
auto delim = lex_ml_basic_string_delim::invoke(inner_loc);
|
auto delim = lex_ml_basic_string_open::invoke(inner_loc);
|
||||||
if(!delim)
|
if(!delim)
|
||||||
{
|
{
|
||||||
throw internal_error(format_underline(
|
throw internal_error(format_underline(
|
||||||
@@ -410,7 +418,26 @@ parse_ml_basic_string(location<Container>& loc)
|
|||||||
{{std::addressof(inner_loc), "not sufficient token"}}),
|
{{std::addressof(inner_loc), "not sufficient token"}}),
|
||||||
source_location(std::addressof(inner_loc)));
|
source_location(std::addressof(inner_loc)));
|
||||||
}
|
}
|
||||||
delim = lex_ml_basic_string_delim::invoke(inner_loc);
|
delim = lex_ml_basic_string_close::invoke(inner_loc);
|
||||||
|
}
|
||||||
|
// `lex_ml_basic_string_close` allows 3 to 5 `"`s to allow 1 or 2 `"`s
|
||||||
|
// at just before the delimiter. Here, we need to attach `"`s at the
|
||||||
|
// end of the string body, if it exists.
|
||||||
|
// For detail, see the definition of `lex_ml_basic_string_close`.
|
||||||
|
assert(std::all_of(delim.unwrap().first(), delim.unwrap().last(),
|
||||||
|
[](const char c) noexcept {return c == '\"';}));
|
||||||
|
switch(delim.unwrap().size())
|
||||||
|
{
|
||||||
|
case 3: {break;}
|
||||||
|
case 4: {retval += "\""; break;}
|
||||||
|
case 5: {retval += "\"\""; break;}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw internal_error(format_underline(
|
||||||
|
"parse_ml_basic_string: closing delimiter has invalid length",
|
||||||
|
{{std::addressof(inner_loc), "end of this"}}),
|
||||||
|
source_location(std::addressof(inner_loc)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ok(std::make_pair(toml::string(retval), token.unwrap()));
|
return ok(std::make_pair(toml::string(retval), token.unwrap()));
|
||||||
}
|
}
|
||||||
@@ -485,7 +512,7 @@ parse_ml_literal_string(location<Container>& loc)
|
|||||||
{
|
{
|
||||||
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||||
|
|
||||||
const auto open = lex_ml_literal_string_delim::invoke(inner_loc);
|
const auto open = lex_ml_literal_string_open::invoke(inner_loc);
|
||||||
if(!open)
|
if(!open)
|
||||||
{
|
{
|
||||||
throw internal_error(format_underline(
|
throw internal_error(format_underline(
|
||||||
@@ -498,7 +525,7 @@ parse_ml_literal_string(location<Container>& loc)
|
|||||||
|
|
||||||
const auto body = lex_ml_literal_body::invoke(inner_loc);
|
const auto body = lex_ml_literal_body::invoke(inner_loc);
|
||||||
|
|
||||||
const auto close = lex_ml_literal_string_delim::invoke(inner_loc);
|
const auto close = lex_ml_literal_string_close::invoke(inner_loc);
|
||||||
if(!close)
|
if(!close)
|
||||||
{
|
{
|
||||||
throw internal_error(format_underline(
|
throw internal_error(format_underline(
|
||||||
@@ -506,8 +533,28 @@ parse_ml_literal_string(location<Container>& loc)
|
|||||||
{{std::addressof(inner_loc), "should be '''"}}),
|
{{std::addressof(inner_loc), "should be '''"}}),
|
||||||
source_location(std::addressof(inner_loc)));
|
source_location(std::addressof(inner_loc)));
|
||||||
}
|
}
|
||||||
return ok(std::make_pair(
|
// `lex_ml_literal_string_close` allows 3 to 5 `'`s to allow 1 or 2 `'`s
|
||||||
toml::string(body.unwrap().str(), toml::string_t::literal),
|
// 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()));
|
token.unwrap()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -694,7 +741,13 @@ parse_local_time(location<Container>& loc)
|
|||||||
case 0: break;
|
case 0: break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
if(sf.size() >= 6)
|
if(sf.size() >= 9)
|
||||||
|
{
|
||||||
|
time.millisecond = from_string<std::uint16_t>(sf.substr(0, 3), 0u);
|
||||||
|
time.microsecond = from_string<std::uint16_t>(sf.substr(3, 3), 0u);
|
||||||
|
time.nanosecond = from_string<std::uint16_t>(sf.substr(6, 3), 0u);
|
||||||
|
}
|
||||||
|
else if(sf.size() >= 6)
|
||||||
{
|
{
|
||||||
time.millisecond = from_string<std::uint16_t>(sf.substr(0, 3), 0u);
|
time.millisecond = from_string<std::uint16_t>(sf.substr(0, 3), 0u);
|
||||||
time.microsecond = from_string<std::uint16_t>(sf.substr(3, 3), 0u);
|
time.microsecond = from_string<std::uint16_t>(sf.substr(3, 3), 0u);
|
||||||
@@ -938,7 +991,12 @@ parse_array(location<Container>& loc)
|
|||||||
|
|
||||||
if(auto val = parse_value<value_type>(loc))
|
if(auto val = parse_value<value_type>(loc))
|
||||||
{
|
{
|
||||||
#ifndef TOML11_USE_UNRELEASED_TOML_FEATURES
|
// After TOML v1.0.0-rc.1, array becomes to be able to have values
|
||||||
|
// with different types. So here we will omit this by default.
|
||||||
|
//
|
||||||
|
// But some of the test-suite checks if the parser accepts a hetero-
|
||||||
|
// geneous arrays, so we keep this for a while.
|
||||||
|
#ifdef TOML11_DISALLOW_HETEROGENEOUS_ARRAYS
|
||||||
if(!retval.empty() && retval.front().type() != val.as_ok().type())
|
if(!retval.empty() && retval.front().type() != val.as_ok().type())
|
||||||
{
|
{
|
||||||
auto array_start_loc = loc;
|
auto array_start_loc = loc;
|
||||||
@@ -1350,9 +1408,6 @@ insert_nested_key(typename Value::table_type& root, const Value& v,
|
|||||||
// According to toml-lang/toml:36d3091b3 "Clarify that inline
|
// According to toml-lang/toml:36d3091b3 "Clarify that inline
|
||||||
// tables are immutable", check if it adds key-value pair to an
|
// tables are immutable", check if it adds key-value pair to an
|
||||||
// inline table.
|
// inline table.
|
||||||
// This is one of the unreleased (after-0.5.0) toml feature.
|
|
||||||
// But this is marked as "Clarify", so TOML-lang intended that
|
|
||||||
// inline tables are immutable in all version.
|
|
||||||
{
|
{
|
||||||
// here, if the value is a (multi-line) table, the region
|
// here, if the value is a (multi-line) table, the region
|
||||||
// should be something like `[table-name]`.
|
// should be something like `[table-name]`.
|
||||||
@@ -2010,10 +2065,11 @@ parse(std::istream& is, const std::string& fname = "unknown file")
|
|||||||
std::vector<char> letters(static_cast<std::size_t>(fsize));
|
std::vector<char> letters(static_cast<std::size_t>(fsize));
|
||||||
is.read(letters.data(), fsize);
|
is.read(letters.data(), fsize);
|
||||||
|
|
||||||
if(!letters.empty() && letters.back() == '\0')
|
while(!letters.empty() && letters.back() == '\0')
|
||||||
{
|
{
|
||||||
letters.pop_back();
|
letters.pop_back();
|
||||||
}
|
}
|
||||||
|
assert(letters.empty() || letters.back() != '\0');
|
||||||
|
|
||||||
detail::location<std::vector<char>>
|
detail::location<std::vector<char>>
|
||||||
loc(std::move(fname), std::move(letters));
|
loc(std::move(fname), std::move(letters));
|
||||||
@@ -2055,5 +2111,39 @@ basic_value<Comment, Table, Array> parse(const std::string& fname)
|
|||||||
return parse<Comment, Table, Array>(ifs, fname);
|
return parse<Comment, Table, Array>(ifs, fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOML11_HAS_STD_FILESYSTEM
|
||||||
|
// This function just forwards `parse("filename.toml")` to std::string version
|
||||||
|
// to avoid the ambiguity in overload resolution.
|
||||||
|
//
|
||||||
|
// Both std::string and std::filesystem::path are convertible from const char[].
|
||||||
|
// Without this, both parse(std::string) and parse(std::filesystem::path)
|
||||||
|
// matches to parse("filename.toml"). This breaks the existing code.
|
||||||
|
//
|
||||||
|
// This function exactly matches to the invokation with string literal.
|
||||||
|
// So this function is preferred than others and the ambiguity disappears.
|
||||||
|
template<typename Comment = ::toml::discard_comments,
|
||||||
|
template<typename ...> class Table = std::unordered_map,
|
||||||
|
template<typename ...> class Array = std::vector,
|
||||||
|
std::size_t N>
|
||||||
|
basic_value<Comment, Table, Array> parse(const char (&fname)[N])
|
||||||
|
{
|
||||||
|
return parse<Comment, Table, Array>(std::string(fname));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Comment = ::toml::discard_comments,
|
||||||
|
template<typename ...> class Table = std::unordered_map,
|
||||||
|
template<typename ...> class Array = std::vector>
|
||||||
|
basic_value<Comment, Table, Array> parse(const std::filesystem::path& fpath)
|
||||||
|
{
|
||||||
|
std::ifstream ifs(fpath, std::ios_base::binary);
|
||||||
|
if(!ifs.good())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("toml::parse: file open error -> " +
|
||||||
|
fpath.string());
|
||||||
|
}
|
||||||
|
return parse<Comment, Table, Array>(ifs, fpath.string());
|
||||||
|
}
|
||||||
|
#endif // TOML11_HAS_STD_FILESYSTEM
|
||||||
|
|
||||||
} // toml
|
} // toml
|
||||||
#endif// TOML11_PARSER_HPP
|
#endif// TOML11_PARSER_HPP
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ inline std::string format_underline(const std::string& message,
|
|||||||
{
|
{
|
||||||
// invalid
|
// invalid
|
||||||
// ~~~~~~~
|
// ~~~~~~~
|
||||||
const auto underline_len = std::min(reg->size(), reg->line().size());
|
const auto underline_len = (std::min)(reg->size(), reg->line().size());
|
||||||
retval << color::bold << color::red
|
retval << color::bold << color::red
|
||||||
<< make_string(underline_len, '~') << color::reset;
|
<< make_string(underline_len, '~') << color::reset;
|
||||||
}
|
}
|
||||||
@@ -511,7 +511,7 @@ inline std::string format_underline(const std::string& message,
|
|||||||
retval << '\n';
|
retval << '\n';
|
||||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
||||||
retval << color::bold << color::blue << " | " << color::reset;
|
retval << color::bold << color::blue << " | " << color::reset;
|
||||||
for(const auto help : helps)
|
for(const auto& help : helps)
|
||||||
{
|
{
|
||||||
retval << color::bold << "\nHint: " << color::reset;
|
retval << color::bold << "\nHint: " << color::reset;
|
||||||
retval << help;
|
retval << help;
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_SERIALIZER_HPP
|
#ifndef TOML11_SERIALIZER_HPP
|
||||||
#define TOML11_SERIALIZER_HPP
|
#define TOML11_SERIALIZER_HPP
|
||||||
#include "value.hpp"
|
|
||||||
#include "lexer.hpp"
|
|
||||||
#include <limits>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include "lexer.hpp"
|
||||||
|
#include "value.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -22,39 +24,62 @@ namespace toml
|
|||||||
// Since toml restricts characters available in a bare key, generally a string
|
// 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
|
// should be escaped. But checking whether a string needs to be surrounded by
|
||||||
// a `"` and escaping some special character is boring.
|
// a `"` and escaping some special character is boring.
|
||||||
inline std::string format_key(const toml::key& key)
|
template<typename charT, typename traits, typename Alloc>
|
||||||
|
std::basic_string<charT, traits, Alloc>
|
||||||
|
format_key(const std::basic_string<charT, traits, Alloc>& key)
|
||||||
{
|
{
|
||||||
|
// check the key can be a bare (unquoted) key
|
||||||
detail::location<toml::key> loc(key, key);
|
detail::location<toml::key> loc(key, key);
|
||||||
detail::lex_unquoted_key::invoke(loc);
|
detail::lex_unquoted_key::invoke(loc);
|
||||||
if(loc.iter() == loc.end())
|
if(loc.iter() == loc.end())
|
||||||
{
|
{
|
||||||
return key; // all the tokens are consumed. the key is unquoted-key.
|
return key; // all the tokens are consumed. the key is unquoted-key.
|
||||||
}
|
}
|
||||||
std::string token("\"");
|
|
||||||
|
//if it includes special characters, then format it in a "quoted" key.
|
||||||
|
std::basic_string<charT, traits, Alloc> serialized("\"");
|
||||||
for(const char c : key)
|
for(const char c : key)
|
||||||
{
|
{
|
||||||
switch(c)
|
switch(c)
|
||||||
{
|
{
|
||||||
case '\\': {token += "\\\\"; break;}
|
case '\\': {serialized += "\\\\"; break;}
|
||||||
case '\"': {token += "\\\""; break;}
|
case '\"': {serialized += "\\\""; break;}
|
||||||
case '\b': {token += "\\b"; break;}
|
case '\b': {serialized += "\\b"; break;}
|
||||||
case '\t': {token += "\\t"; break;}
|
case '\t': {serialized += "\\t"; break;}
|
||||||
case '\f': {token += "\\f"; break;}
|
case '\f': {serialized += "\\f"; break;}
|
||||||
case '\n': {token += "\\n"; break;}
|
case '\n': {serialized += "\\n"; break;}
|
||||||
case '\r': {token += "\\r"; break;}
|
case '\r': {serialized += "\\r"; break;}
|
||||||
default : {token += c; break;}
|
default : {serialized += c; break;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
token += "\"";
|
serialized += "\"";
|
||||||
return token;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Comment,
|
template<typename charT, typename traits, typename Alloc>
|
||||||
template<typename ...> class Table,
|
std::basic_string<charT, traits, Alloc>
|
||||||
template<typename ...> class Array>
|
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>
|
||||||
struct serializer
|
struct serializer
|
||||||
{
|
{
|
||||||
using value_type = basic_value<Comment, Table, Array>;
|
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 key_type = typename value_type::key_type ;
|
using key_type = typename value_type::key_type ;
|
||||||
using comment_type = typename value_type::comment_type ;
|
using comment_type = typename value_type::comment_type ;
|
||||||
using boolean_type = typename value_type::boolean_type ;
|
using boolean_type = typename value_type::boolean_type ;
|
||||||
@@ -112,35 +137,6 @@ struct serializer
|
|||||||
{
|
{
|
||||||
// the resulting value does not have any float specific part!
|
// the resulting value does not have any float specific part!
|
||||||
token += ".0";
|
token += ".0";
|
||||||
return token;
|
|
||||||
}
|
|
||||||
if(!has_exponent)
|
|
||||||
{
|
|
||||||
return token; // there is no exponent part. just return it.
|
|
||||||
}
|
|
||||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
|
||||||
// Although currently it is not released yet, TOML will allow
|
|
||||||
// zero-prefix in an exponent part such as 1.234e+01.
|
|
||||||
// The following code removes the zero prefixes.
|
|
||||||
// If the feature is activated, the following codes can be skipped.
|
|
||||||
return token;
|
|
||||||
#endif
|
|
||||||
// zero-prefix in an exponent is NOT allowed in TOML v0.5.0.
|
|
||||||
// remove it if it exists.
|
|
||||||
bool sign_exists = false;
|
|
||||||
std::size_t zero_prefix = 0;
|
|
||||||
for(auto iter = std::next(e), iend = token.cend(); iter != iend; ++iter)
|
|
||||||
{
|
|
||||||
if(*iter == '+' || *iter == '-'){sign_exists = true; continue;}
|
|
||||||
if(*iter == '0'){zero_prefix += 1;}
|
|
||||||
else {break;}
|
|
||||||
}
|
|
||||||
if(zero_prefix != 0)
|
|
||||||
{
|
|
||||||
const auto offset = std::distance(token.cbegin(), e) +
|
|
||||||
(sign_exists ? 2 : 1);
|
|
||||||
token.erase(static_cast<typename std::string::size_type>(offset),
|
|
||||||
zero_prefix);
|
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -148,12 +144,23 @@ struct serializer
|
|||||||
{
|
{
|
||||||
if(s.kind == string_t::basic)
|
if(s.kind == string_t::basic)
|
||||||
{
|
{
|
||||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
|
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||||
|
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend())
|
||||||
{
|
{
|
||||||
// if linefeed is contained, make it multiline-string.
|
// if linefeed or double-quote is contained,
|
||||||
const std::string open("\"\"\"\n");
|
// make it multiline basic string.
|
||||||
const std::string close("\\\n\"\"\"");
|
const auto escaped = this->escape_ml_basic_string(s.str);
|
||||||
return open + this->escape_ml_basic_string(s.str) + close;
|
std::string open("\"\"\"");
|
||||||
|
std::string close("\"\"\"");
|
||||||
|
if(escaped.find('\n') != std::string::npos ||
|
||||||
|
this->width_ < escaped.size() + 6)
|
||||||
|
{
|
||||||
|
// if the string body contains newline or is enough long,
|
||||||
|
// add newlines after and before delimiters.
|
||||||
|
open += "\n";
|
||||||
|
close = std::string("\\\n") + close;
|
||||||
|
}
|
||||||
|
return open + escaped + close;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no linefeed. try to make it oneline-string.
|
// no linefeed. try to make it oneline-string.
|
||||||
@@ -194,7 +201,11 @@ struct serializer
|
|||||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||||
std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
|
std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
|
||||||
{
|
{
|
||||||
const std::string open("'''\n");
|
std::string open("'''");
|
||||||
|
if(this->width_ + 6 < s.str.size())
|
||||||
|
{
|
||||||
|
open += '\n'; // the first newline is ignored by TOML spec
|
||||||
|
}
|
||||||
const std::string close("'''");
|
const std::string close("'''");
|
||||||
return open + s.str + close;
|
return open + s.str + close;
|
||||||
}
|
}
|
||||||
@@ -249,7 +260,7 @@ struct serializer
|
|||||||
std::string token;
|
std::string token;
|
||||||
if(!keys_.empty())
|
if(!keys_.empty())
|
||||||
{
|
{
|
||||||
token += this->serialize_key(keys_.back());
|
token += format_key(keys_.back());
|
||||||
token += " = ";
|
token += " = ";
|
||||||
}
|
}
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
@@ -305,7 +316,7 @@ struct serializer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
token += "[[";
|
token += "[[";
|
||||||
token += this->serialize_dotted_key(keys_);
|
token += format_keys(keys_);
|
||||||
token += "]]\n";
|
token += "]]\n";
|
||||||
token += this->make_multiline_table(item.as_table());
|
token += this->make_multiline_table(item.as_table());
|
||||||
}
|
}
|
||||||
@@ -417,7 +428,7 @@ struct serializer
|
|||||||
std::string token;
|
std::string token;
|
||||||
if(!this->keys_.empty())
|
if(!this->keys_.empty())
|
||||||
{
|
{
|
||||||
token += this->serialize_key(this->keys_.back());
|
token += format_key(this->keys_.back());
|
||||||
token += " = ";
|
token += " = ";
|
||||||
}
|
}
|
||||||
token += this->make_inline_table(v);
|
token += this->make_inline_table(v);
|
||||||
@@ -432,7 +443,7 @@ struct serializer
|
|||||||
if(!keys_.empty())
|
if(!keys_.empty())
|
||||||
{
|
{
|
||||||
token += '[';
|
token += '[';
|
||||||
token += this->serialize_dotted_key(keys_);
|
token += format_keys(keys_);
|
||||||
token += "]\n";
|
token += "]\n";
|
||||||
}
|
}
|
||||||
token += this->make_multiline_table(v);
|
token += this->make_multiline_table(v);
|
||||||
@@ -441,25 +452,6 @@ struct serializer
|
|||||||
|
|
||||||
private:
|
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
|
std::string escape_basic_string(const std::string& s) const
|
||||||
{
|
{
|
||||||
//XXX assuming `s` is a valid utf-8 sequence.
|
//XXX assuming `s` is a valid utf-8 sequence.
|
||||||
@@ -489,7 +481,9 @@ struct serializer
|
|||||||
switch(*i)
|
switch(*i)
|
||||||
{
|
{
|
||||||
case '\\': {retval += "\\\\"; break;}
|
case '\\': {retval += "\\\\"; break;}
|
||||||
case '\"': {retval += "\\\""; break;}
|
// One or two consecutive "s are allowed.
|
||||||
|
// Later we will check there are no three consecutive "s.
|
||||||
|
// case '\"': {retval += "\\\""; break;}
|
||||||
case '\b': {retval += "\\b"; break;}
|
case '\b': {retval += "\\b"; break;}
|
||||||
case '\t': {retval += "\\t"; break;}
|
case '\t': {retval += "\\t"; break;}
|
||||||
case '\f': {retval += "\\f"; break;}
|
case '\f': {retval += "\\f"; break;}
|
||||||
@@ -510,6 +504,23 @@ struct serializer
|
|||||||
default: {retval += *i; break;}
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +557,7 @@ struct serializer
|
|||||||
for(const auto& item : v)
|
for(const auto& item : v)
|
||||||
{
|
{
|
||||||
if(is_first) {is_first = false;} else {token += ',';}
|
if(is_first) {is_first = false;} else {token += ',';}
|
||||||
token += visit(serializer(std::numeric_limits<std::size_t>::max(),
|
token += visit(serializer((std::numeric_limits<std::size_t>::max)(),
|
||||||
this->float_prec_, true), item);
|
this->float_prec_, true), item);
|
||||||
}
|
}
|
||||||
token += ']';
|
token += ']';
|
||||||
@@ -564,9 +575,9 @@ struct serializer
|
|||||||
{
|
{
|
||||||
// in inline tables, trailing comma is not allowed (toml-lang #569).
|
// in inline tables, trailing comma is not allowed (toml-lang #569).
|
||||||
if(is_first) {is_first = false;} else {token += ',';}
|
if(is_first) {is_first = false;} else {token += ',';}
|
||||||
token += this->serialize_key(kv.first);
|
token += format_key(kv.first);
|
||||||
token += '=';
|
token += '=';
|
||||||
token += visit(serializer(std::numeric_limits<std::size_t>::max(),
|
token += visit(serializer((std::numeric_limits<std::size_t>::max)(),
|
||||||
this->float_prec_, true), kv.second);
|
this->float_prec_, true), kv.second);
|
||||||
}
|
}
|
||||||
token += '}';
|
token += '}';
|
||||||
@@ -579,7 +590,7 @@ struct serializer
|
|||||||
|
|
||||||
// print non-table stuff first. because after printing [foo.bar], the
|
// print non-table stuff first. because after printing [foo.bar], the
|
||||||
// remaining non-table values will be assigned into [foo.bar], not [foo]
|
// 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))
|
if(kv.second.is_table() || is_array_of_tables(kv.second))
|
||||||
{
|
{
|
||||||
@@ -595,7 +606,7 @@ struct serializer
|
|||||||
token += '\n';
|
token += '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto key_and_sep = this->serialize_key(kv.first) + " = ";
|
const auto key_and_sep = format_key(kv.first) + " = ";
|
||||||
const auto residual_width = (this->width_ > key_and_sep.size()) ?
|
const auto residual_width = (this->width_ > key_and_sep.size()) ?
|
||||||
this->width_ - key_and_sep.size() : 0;
|
this->width_ - key_and_sep.size() : 0;
|
||||||
token += key_and_sep;
|
token += key_and_sep;
|
||||||
@@ -677,6 +688,7 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
|||||||
int fprec = std::numeric_limits<toml::floating>::max_digits10,
|
int fprec = std::numeric_limits<toml::floating>::max_digits10,
|
||||||
bool no_comment = false, bool force_inline = false)
|
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.
|
// if value is a table, it is considered to be a root object.
|
||||||
// the root object can't be an inline table.
|
// the root object can't be an inline table.
|
||||||
if(v.is_table())
|
if(v.is_table())
|
||||||
@@ -687,10 +699,11 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
|||||||
oss << v.comments();
|
oss << v.comments();
|
||||||
oss << '\n'; // to split the file comment from the first element
|
oss << '\n'; // to split the file comment from the first element
|
||||||
}
|
}
|
||||||
oss << visit(serializer<C, M, V>(w, fprec, no_comment, false), v);
|
const auto serialized = visit(serializer<value_type>(w, fprec, no_comment, false), v);
|
||||||
|
oss << serialized;
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
return visit(serializer<C, M, V>(w, fprec, force_inline), v);
|
return visit(serializer<value_type>(w, fprec, force_inline), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
@@ -726,6 +739,8 @@ template<typename charT, typename traits, typename C,
|
|||||||
std::basic_ostream<charT, traits>&
|
std::basic_ostream<charT, traits>&
|
||||||
operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
|
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().
|
// get status of std::setw().
|
||||||
const auto w = static_cast<std::size_t>(os.width());
|
const auto w = static_cast<std::size_t>(os.width());
|
||||||
const int fprec = static_cast<int>(os.precision());
|
const int fprec = static_cast<int>(os.precision());
|
||||||
@@ -741,7 +756,8 @@ 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
|
os << '\n'; // to split the file comment from the first element
|
||||||
}
|
}
|
||||||
// the root object can't be an inline table. so pass `false`.
|
// the root object can't be an inline table. so pass `false`.
|
||||||
os << visit(serializer<C, M, V>(w, fprec, false, no_comment), v);
|
const auto serialized = visit(serializer<value_type>(w, fprec, no_comment, false), v);
|
||||||
|
os << serialized;
|
||||||
|
|
||||||
// if v is a non-table value, and has only one comment, then
|
// if v is a non-table value, and has only one comment, then
|
||||||
// put a comment just after a value. in the following way.
|
// put a comment just after a value. in the following way.
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_SOURCE_LOCATION_HPP
|
#ifndef TOML11_SOURCE_LOCATION_HPP
|
||||||
#define TOML11_SOURCE_LOCATION_HPP
|
#define TOML11_SOURCE_LOCATION_HPP
|
||||||
#include "region.hpp"
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "region.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_STRING_HPP
|
#ifndef TOML11_STRING_HPP
|
||||||
#define TOML11_STRING_HPP
|
#define TOML11_STRING_HPP
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
|
||||||
#if __cplusplus >= 201703L
|
#if __cplusplus >= 201703L
|
||||||
#if __has_include(<string_view>)
|
#if __has_include(<string_view>)
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_TRAITS_HPP
|
#ifndef TOML11_TRAITS_HPP
|
||||||
#define TOML11_TRAITS_HPP
|
#define TOML11_TRAITS_HPP
|
||||||
|
#include <chrono>
|
||||||
|
#include <forward_list>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <chrono>
|
|
||||||
#include <tuple>
|
|
||||||
#include <string>
|
|
||||||
#if __cplusplus >= 201703L
|
#if __cplusplus >= 201703L
|
||||||
#if __has_include(<string_view>)
|
#if __has_include(<string_view>)
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -43,17 +45,23 @@ struct has_mapped_type_impl
|
|||||||
template<typename T> static std::true_type check(typename T::mapped_type*);
|
template<typename T> static std::true_type check(typename T::mapped_type*);
|
||||||
template<typename T> static std::false_type check(...);
|
template<typename T> static std::false_type check(...);
|
||||||
};
|
};
|
||||||
struct has_resize_method_impl
|
struct has_reserve_method_impl
|
||||||
{
|
{
|
||||||
constexpr static std::size_t dummy=0;
|
|
||||||
template<typename T> static std::true_type check(decltype(std::declval<T>().resize(dummy))*);
|
|
||||||
template<typename T> static std::false_type check(...);
|
template<typename T> static std::false_type check(...);
|
||||||
|
template<typename T> static std::true_type check(
|
||||||
|
decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
|
||||||
|
};
|
||||||
|
struct has_push_back_method_impl
|
||||||
|
{
|
||||||
|
template<typename T> static std::false_type check(...);
|
||||||
|
template<typename T> static std::true_type check(
|
||||||
|
decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct is_comparable_impl
|
struct is_comparable_impl
|
||||||
{
|
{
|
||||||
template<typename T> static std::true_type check(decltype(std::declval<T>() < std::declval<T>())*);
|
|
||||||
template<typename T> static std::false_type check(...);
|
template<typename T> static std::false_type check(...);
|
||||||
|
template<typename T> static std::true_type check(
|
||||||
|
decltype(std::declval<T>() < std::declval<T>())*);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct has_from_toml_method_impl
|
struct has_from_toml_method_impl
|
||||||
@@ -91,7 +99,9 @@ struct has_key_type : decltype(has_key_type_impl::check<T>(nullptr)){};
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
|
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
|
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
|
||||||
|
template<typename T>
|
||||||
|
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
|
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
|
||||||
|
|
||||||
@@ -149,6 +159,10 @@ template<typename T> struct is_std_tuple : std::false_type{};
|
|||||||
template<typename ... Ts>
|
template<typename ... Ts>
|
||||||
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
|
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
|
||||||
|
|
||||||
|
template<typename T> struct is_std_forward_list : std::false_type{};
|
||||||
|
template<typename T>
|
||||||
|
struct is_std_forward_list<std::forward_list<T>> : std::true_type{};
|
||||||
|
|
||||||
template<typename T> struct is_chrono_duration: std::false_type{};
|
template<typename T> struct is_chrono_duration: std::false_type{};
|
||||||
template<typename Rep, typename Period>
|
template<typename Rep, typename Period>
|
||||||
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
|
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_TYPES_HPP
|
#ifndef TOML11_TYPES_HPP
|
||||||
#define TOML11_TYPES_HPP
|
#define TOML11_TYPES_HPP
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "comments.hpp"
|
||||||
#include "datetime.hpp"
|
#include "datetime.hpp"
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
#include "traits.hpp"
|
#include "traits.hpp"
|
||||||
#include "comments.hpp"
|
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_UTILITY_HPP
|
#ifndef TOML11_UTILITY_HPP
|
||||||
#define TOML11_UTILITY_HPP
|
#define TOML11_UTILITY_HPP
|
||||||
#include "traits.hpp"
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "traits.hpp"
|
||||||
|
|
||||||
#if __cplusplus >= 201402L
|
#if __cplusplus >= 201402L
|
||||||
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
|
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
|
||||||
@@ -36,30 +37,25 @@ inline std::unique_ptr<T> make_unique(Ts&& ... args)
|
|||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
template<typename Container>
|
||||||
template<typename T>
|
void try_reserve_impl(Container& container, std::size_t N, std::true_type)
|
||||||
inline void resize_impl(T& container, std::size_t N, std::true_type)
|
|
||||||
{
|
{
|
||||||
container.resize(N);
|
container.reserve(N);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
template<typename Container>
|
||||||
template<typename T>
|
void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
|
||||||
inline void resize_impl(T& container, std::size_t N, std::false_type)
|
|
||||||
{
|
{
|
||||||
if(container.size() >= N) {return;}
|
return;
|
||||||
|
|
||||||
throw std::invalid_argument("not resizable type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
template<typename T>
|
template<typename Container>
|
||||||
inline void resize(T& container, std::size_t N)
|
void try_reserve(Container& container, std::size_t N)
|
||||||
{
|
{
|
||||||
if(container.size() == N) {return;}
|
if(N <= container.size()) {return;}
|
||||||
|
detail::try_reserve_impl(container, N, detail::has_reserve_method<Container>{});
|
||||||
return detail::resize_impl(container, N, detail::has_resize_method<T>());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|||||||
615
toml/value.hpp
615
toml/value.hpp
@@ -2,17 +2,18 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_VALUE_HPP
|
#ifndef TOML11_VALUE_HPP
|
||||||
#define TOML11_VALUE_HPP
|
#define TOML11_VALUE_HPP
|
||||||
#include "traits.hpp"
|
|
||||||
#include "into.hpp"
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "exception.hpp"
|
|
||||||
#include "storage.hpp"
|
|
||||||
#include "region.hpp"
|
|
||||||
#include "types.hpp"
|
|
||||||
#include "source_location.hpp"
|
|
||||||
#include "comments.hpp"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "comments.hpp"
|
||||||
|
#include "exception.hpp"
|
||||||
|
#include "into.hpp"
|
||||||
|
#include "region.hpp"
|
||||||
|
#include "source_location.hpp"
|
||||||
|
#include "storage.hpp"
|
||||||
|
#include "traits.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -20,223 +21,145 @@ namespace detail
|
|||||||
{
|
{
|
||||||
|
|
||||||
// to show error messages. not recommended for users.
|
// to show error messages. not recommended for users.
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
template<typename Value>
|
||||||
region_base const& get_region(const basic_value<C, T, A>&);
|
inline region_base const& get_region(const Value& v)
|
||||||
template<typename Region,
|
|
||||||
typename C, template<typename ...> class T, template<typename ...> class A>
|
|
||||||
void change_region(basic_value<C, T, A>&, Region&&);
|
|
||||||
|
|
||||||
template<value_t Expected,
|
|
||||||
typename C, template<typename ...> class T, template<typename ...> class A>
|
|
||||||
[[noreturn]] inline void
|
|
||||||
throw_bad_cast(value_t actual, const ::toml::basic_value<C, T, A>& v)
|
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline(concat_to_string(
|
return *(v.region_info_);
|
||||||
"toml::value: bad_cast to ", Expected), {
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
[[noreturn]] inline void
|
||||||
|
throw_bad_cast(const std::string& funcname, value_t actual, const Value& v)
|
||||||
|
{
|
||||||
|
throw type_error(detail::format_underline(
|
||||||
|
concat_to_string(funcname, "bad_cast to ", Expected), {
|
||||||
{std::addressof(get_region(v)),
|
{std::addressof(get_region(v)),
|
||||||
concat_to_string("the actual type is ", actual)}
|
concat_to_string("the actual type is ", actual)}
|
||||||
}), v.location());
|
}), v.location());
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch by `value_t` and call the corresponding `value::as_xxx()`. {{{
|
// 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.
|
||||||
template<value_t T>
|
template<value_t T>
|
||||||
struct switch_cast {};
|
struct switch_cast {};
|
||||||
template<>
|
#define TOML11_GENERATE_SWITCH_CASTER(TYPE) \
|
||||||
struct switch_cast<value_t::boolean>
|
template<> \
|
||||||
{
|
struct switch_cast<value_t::TYPE> \
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
{ \
|
||||||
static ::toml::boolean& invoke(basic_value<C, T, A>& v) noexcept
|
template<typename Value> \
|
||||||
{
|
static typename Value::TYPE##_type& invoke(Value& v) \
|
||||||
return v.as_boolean();
|
{ \
|
||||||
}
|
return v.as_##TYPE(); \
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
} \
|
||||||
static ::toml::boolean const& invoke(basic_value<C, T, A> const& v) noexcept
|
template<typename Value> \
|
||||||
{
|
static typename Value::TYPE##_type const& invoke(const Value& v) \
|
||||||
return v.as_boolean();
|
{ \
|
||||||
}
|
return v.as_##TYPE(); \
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
} \
|
||||||
static ::toml::boolean&& invoke(basic_value<C, T, A>&& v) noexcept
|
template<typename Value> \
|
||||||
{
|
static typename Value::TYPE##_type&& invoke(Value&& v) \
|
||||||
return std::move(v).as_boolean();
|
{ \
|
||||||
}
|
return std::move(v).as_##TYPE(); \
|
||||||
};
|
} \
|
||||||
template<>
|
}; \
|
||||||
struct switch_cast<value_t::integer>
|
/**/
|
||||||
{
|
TOML11_GENERATE_SWITCH_CASTER(boolean)
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
TOML11_GENERATE_SWITCH_CASTER(integer)
|
||||||
static ::toml::integer& invoke(basic_value<C, T, A>& v) noexcept
|
TOML11_GENERATE_SWITCH_CASTER(floating)
|
||||||
{
|
TOML11_GENERATE_SWITCH_CASTER(string)
|
||||||
return v.as_integer();
|
TOML11_GENERATE_SWITCH_CASTER(offset_datetime)
|
||||||
}
|
TOML11_GENERATE_SWITCH_CASTER(local_datetime)
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
TOML11_GENERATE_SWITCH_CASTER(local_date)
|
||||||
static ::toml::integer const& invoke(basic_value<C, T, A> const& v) noexcept
|
TOML11_GENERATE_SWITCH_CASTER(local_time)
|
||||||
{
|
TOML11_GENERATE_SWITCH_CASTER(array)
|
||||||
return v.as_integer();
|
TOML11_GENERATE_SWITCH_CASTER(table)
|
||||||
}
|
|
||||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
#undef TOML11_GENERATE_SWITCH_CASTER
|
||||||
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
|
}// detail
|
||||||
|
|
||||||
@@ -1255,7 +1178,7 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != T)
|
if(this->type_ != T)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<T>(this->type_, *this);
|
detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return detail::switch_cast<T>::invoke(*this);
|
return detail::switch_cast<T>::invoke(*this);
|
||||||
}
|
}
|
||||||
@@ -1264,7 +1187,7 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != T)
|
if(this->type_ != T)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<T>(this->type_, *this);
|
detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return detail::switch_cast<T>::invoke(*this);
|
return detail::switch_cast<T>::invoke(*this);
|
||||||
}
|
}
|
||||||
@@ -1273,7 +1196,7 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != T)
|
if(this->type_ != T)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<T>(this->type_, *this);
|
detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return detail::switch_cast<T>::invoke(std::move(*this));
|
return detail::switch_cast<T>::invoke(std::move(*this));
|
||||||
}
|
}
|
||||||
@@ -1317,13 +1240,14 @@ class basic_value
|
|||||||
// ========================================================================
|
// ========================================================================
|
||||||
// throw version
|
// throw version
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// const reference
|
// const reference {{{
|
||||||
|
|
||||||
boolean const& as_boolean() const&
|
boolean const& as_boolean() const&
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::boolean)
|
if(this->type_ != value_t::boolean)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::boolean>(this->type_, *this);
|
detail::throw_bad_cast<value_t::boolean>(
|
||||||
|
"toml::value::as_boolean(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->boolean_;
|
return this->boolean_;
|
||||||
}
|
}
|
||||||
@@ -1331,7 +1255,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::integer)
|
if(this->type_ != value_t::integer)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::integer>(this->type_, *this);
|
detail::throw_bad_cast<value_t::integer>(
|
||||||
|
"toml::value::as_integer(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->integer_;
|
return this->integer_;
|
||||||
}
|
}
|
||||||
@@ -1339,7 +1264,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::floating)
|
if(this->type_ != value_t::floating)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::floating>(this->type_, *this);
|
detail::throw_bad_cast<value_t::floating>(
|
||||||
|
"toml::value::as_floating(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->floating_;
|
return this->floating_;
|
||||||
}
|
}
|
||||||
@@ -1347,7 +1273,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::string)
|
if(this->type_ != value_t::string)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::string>(this->type_, *this);
|
detail::throw_bad_cast<value_t::string>(
|
||||||
|
"toml::value::as_string(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->string_;
|
return this->string_;
|
||||||
}
|
}
|
||||||
@@ -1355,7 +1282,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::offset_datetime)
|
if(this->type_ != value_t::offset_datetime)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::offset_datetime>(this->type_, *this);
|
detail::throw_bad_cast<value_t::offset_datetime>(
|
||||||
|
"toml::value::as_offset_datetime(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->offset_datetime_;
|
return this->offset_datetime_;
|
||||||
}
|
}
|
||||||
@@ -1363,7 +1291,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_datetime)
|
if(this->type_ != value_t::local_datetime)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_datetime>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_datetime>(
|
||||||
|
"toml::value::as_local_datetime(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->local_datetime_;
|
return this->local_datetime_;
|
||||||
}
|
}
|
||||||
@@ -1371,7 +1300,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_date)
|
if(this->type_ != value_t::local_date)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_date>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_date>(
|
||||||
|
"toml::value::as_local_date(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->local_date_;
|
return this->local_date_;
|
||||||
}
|
}
|
||||||
@@ -1379,7 +1309,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_time)
|
if(this->type_ != value_t::local_time)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_time>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_time>(
|
||||||
|
"toml::value::as_local_time(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->local_time_;
|
return this->local_time_;
|
||||||
}
|
}
|
||||||
@@ -1387,7 +1318,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::array)
|
if(this->type_ != value_t::array)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::array>(this->type_, *this);
|
detail::throw_bad_cast<value_t::array>(
|
||||||
|
"toml::value::as_array(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->array_.value();
|
return this->array_.value();
|
||||||
}
|
}
|
||||||
@@ -1395,19 +1327,21 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::table)
|
if(this->type_ != value_t::table)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::table>(this->type_, *this);
|
detail::throw_bad_cast<value_t::table>(
|
||||||
|
"toml::value::as_table(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->table_.value();
|
return this->table_.value();
|
||||||
}
|
}
|
||||||
|
// }}}
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// nonconst reference
|
// nonconst reference {{{
|
||||||
|
|
||||||
boolean & as_boolean() &
|
boolean & as_boolean() &
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::boolean)
|
if(this->type_ != value_t::boolean)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::boolean>(this->type_, *this);
|
detail::throw_bad_cast<value_t::boolean>(
|
||||||
|
"toml::value::as_boolean(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->boolean_;
|
return this->boolean_;
|
||||||
}
|
}
|
||||||
@@ -1415,7 +1349,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::integer)
|
if(this->type_ != value_t::integer)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::integer>(this->type_, *this);
|
detail::throw_bad_cast<value_t::integer>(
|
||||||
|
"toml::value::as_integer(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->integer_;
|
return this->integer_;
|
||||||
}
|
}
|
||||||
@@ -1423,7 +1358,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::floating)
|
if(this->type_ != value_t::floating)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::floating>(this->type_, *this);
|
detail::throw_bad_cast<value_t::floating>(
|
||||||
|
"toml::value::as_floating(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->floating_;
|
return this->floating_;
|
||||||
}
|
}
|
||||||
@@ -1431,7 +1367,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::string)
|
if(this->type_ != value_t::string)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::string>(this->type_, *this);
|
detail::throw_bad_cast<value_t::string>(
|
||||||
|
"toml::value::as_string(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->string_;
|
return this->string_;
|
||||||
}
|
}
|
||||||
@@ -1439,7 +1376,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::offset_datetime)
|
if(this->type_ != value_t::offset_datetime)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::offset_datetime>(this->type_, *this);
|
detail::throw_bad_cast<value_t::offset_datetime>(
|
||||||
|
"toml::value::as_offset_datetime(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->offset_datetime_;
|
return this->offset_datetime_;
|
||||||
}
|
}
|
||||||
@@ -1447,7 +1385,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_datetime)
|
if(this->type_ != value_t::local_datetime)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_datetime>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_datetime>(
|
||||||
|
"toml::value::as_local_datetime(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->local_datetime_;
|
return this->local_datetime_;
|
||||||
}
|
}
|
||||||
@@ -1455,7 +1394,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_date)
|
if(this->type_ != value_t::local_date)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_date>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_date>(
|
||||||
|
"toml::value::as_local_date(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->local_date_;
|
return this->local_date_;
|
||||||
}
|
}
|
||||||
@@ -1463,7 +1403,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_time)
|
if(this->type_ != value_t::local_time)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_time>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_time>(
|
||||||
|
"toml::value::as_local_time(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->local_time_;
|
return this->local_time_;
|
||||||
}
|
}
|
||||||
@@ -1471,7 +1412,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::array)
|
if(this->type_ != value_t::array)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::array>(this->type_, *this);
|
detail::throw_bad_cast<value_t::array>(
|
||||||
|
"toml::value::as_array(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->array_.value();
|
return this->array_.value();
|
||||||
}
|
}
|
||||||
@@ -1479,19 +1421,22 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::table)
|
if(this->type_ != value_t::table)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::table>(this->type_, *this);
|
detail::throw_bad_cast<value_t::table>(
|
||||||
|
"toml::value::as_table(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return this->table_.value();
|
return this->table_.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// rvalue reference
|
// rvalue reference {{{
|
||||||
|
|
||||||
boolean && as_boolean() &&
|
boolean && as_boolean() &&
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::boolean)
|
if(this->type_ != value_t::boolean)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::boolean>(this->type_, *this);
|
detail::throw_bad_cast<value_t::boolean>(
|
||||||
|
"toml::value::as_boolean(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->boolean_);
|
return std::move(this->boolean_);
|
||||||
}
|
}
|
||||||
@@ -1499,7 +1444,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::integer)
|
if(this->type_ != value_t::integer)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::integer>(this->type_, *this);
|
detail::throw_bad_cast<value_t::integer>(
|
||||||
|
"toml::value::as_integer(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->integer_);
|
return std::move(this->integer_);
|
||||||
}
|
}
|
||||||
@@ -1507,7 +1453,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::floating)
|
if(this->type_ != value_t::floating)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::floating>(this->type_, *this);
|
detail::throw_bad_cast<value_t::floating>(
|
||||||
|
"toml::value::as_floating(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->floating_);
|
return std::move(this->floating_);
|
||||||
}
|
}
|
||||||
@@ -1515,7 +1462,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::string)
|
if(this->type_ != value_t::string)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::string>(this->type_, *this);
|
detail::throw_bad_cast<value_t::string>(
|
||||||
|
"toml::value::as_string(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->string_);
|
return std::move(this->string_);
|
||||||
}
|
}
|
||||||
@@ -1523,7 +1471,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::offset_datetime)
|
if(this->type_ != value_t::offset_datetime)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::offset_datetime>(this->type_, *this);
|
detail::throw_bad_cast<value_t::offset_datetime>(
|
||||||
|
"toml::value::as_offset_datetime(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->offset_datetime_);
|
return std::move(this->offset_datetime_);
|
||||||
}
|
}
|
||||||
@@ -1531,7 +1480,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_datetime)
|
if(this->type_ != value_t::local_datetime)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_datetime>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_datetime>(
|
||||||
|
"toml::value::as_local_datetime(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->local_datetime_);
|
return std::move(this->local_datetime_);
|
||||||
}
|
}
|
||||||
@@ -1539,7 +1489,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_date)
|
if(this->type_ != value_t::local_date)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_date>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_date>(
|
||||||
|
"toml::value::as_local_date(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->local_date_);
|
return std::move(this->local_date_);
|
||||||
}
|
}
|
||||||
@@ -1547,7 +1498,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::local_time)
|
if(this->type_ != value_t::local_time)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::local_time>(this->type_, *this);
|
detail::throw_bad_cast<value_t::local_time>(
|
||||||
|
"toml::value::as_local_time(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->local_time_);
|
return std::move(this->local_time_);
|
||||||
}
|
}
|
||||||
@@ -1555,7 +1507,8 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::array)
|
if(this->type_ != value_t::array)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::array>(this->type_, *this);
|
detail::throw_bad_cast<value_t::array>(
|
||||||
|
"toml::value::as_array(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->array_.value());
|
return std::move(this->array_.value());
|
||||||
}
|
}
|
||||||
@@ -1563,10 +1516,12 @@ class basic_value
|
|||||||
{
|
{
|
||||||
if(this->type_ != value_t::table)
|
if(this->type_ != value_t::table)
|
||||||
{
|
{
|
||||||
detail::throw_bad_cast<value_t::table>(this->type_, *this);
|
detail::throw_bad_cast<value_t::table>(
|
||||||
|
"toml::value::as_table(): ", this->type_, *this);
|
||||||
}
|
}
|
||||||
return std::move(this->table_.value());
|
return std::move(this->table_.value());
|
||||||
}
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
// accessors =============================================================
|
// accessors =============================================================
|
||||||
//
|
//
|
||||||
@@ -1574,11 +1529,29 @@ class basic_value
|
|||||||
//
|
//
|
||||||
value_type& at(const key& k)
|
value_type& at(const key& k)
|
||||||
{
|
{
|
||||||
return this->as_table().at(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);
|
||||||
}
|
}
|
||||||
value_type const& at(const key& k) const
|
value_type const& at(const key& k) const
|
||||||
{
|
{
|
||||||
return this->as_table().at(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);
|
||||||
}
|
}
|
||||||
value_type& operator[](const key& k)
|
value_type& operator[](const key& k)
|
||||||
{
|
{
|
||||||
@@ -1586,49 +1559,78 @@ class basic_value
|
|||||||
{
|
{
|
||||||
*this = table_type{};
|
*this = table_type{};
|
||||||
}
|
}
|
||||||
return this->as_table()[k];
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type& at(const std::size_t idx)
|
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);
|
return this->as_array().at(idx);
|
||||||
}
|
}
|
||||||
value_type const& at(const std::size_t idx) const
|
value_type const& at(const std::size_t idx) const
|
||||||
{
|
{
|
||||||
return this->as_array().at(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(std::nothrow).at(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type& operator[](const std::size_t idx) noexcept
|
value_type& operator[](const std::size_t idx) noexcept
|
||||||
{
|
{
|
||||||
|
// no check...
|
||||||
return this->as_array(std::nothrow)[idx];
|
return this->as_array(std::nothrow)[idx];
|
||||||
}
|
}
|
||||||
value_type const& operator[](const std::size_t idx) const noexcept
|
value_type const& operator[](const std::size_t idx) const noexcept
|
||||||
{
|
{
|
||||||
|
// no check...
|
||||||
return this->as_array(std::nothrow)[idx];
|
return this->as_array(std::nothrow)[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const value_type& x)
|
void push_back(const value_type& x)
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::array)
|
if(!this->is_array())
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline(
|
detail::throw_bad_cast<value_t::array>(
|
||||||
"toml::value::push_back(value): bad_cast to array type", {
|
"toml::value::push_back(value): ", this->type_, *this);
|
||||||
{this->region_info_.get(),
|
|
||||||
concat_to_string("the actual type is ", this->type_)}
|
|
||||||
}), this->location());
|
|
||||||
}
|
}
|
||||||
this->as_array(std::nothrow).push_back(x);
|
this->as_array(std::nothrow).push_back(x);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void push_back(value_type&& x)
|
void push_back(value_type&& x)
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::array)
|
if(!this->is_array())
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline(
|
detail::throw_bad_cast<value_t::array>(
|
||||||
"toml::value::push_back(value): bad_cast to array type", {
|
"toml::value::push_back(value): ", this->type_, *this);
|
||||||
{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));
|
this->as_array(std::nothrow).push_back(std::move(x));
|
||||||
return;
|
return;
|
||||||
@@ -1637,13 +1639,10 @@ class basic_value
|
|||||||
template<typename ... Ts>
|
template<typename ... Ts>
|
||||||
value_type& emplace_back(Ts&& ... args)
|
value_type& emplace_back(Ts&& ... args)
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::array)
|
if(!this->is_array())
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline(
|
detail::throw_bad_cast<value_t::array>(
|
||||||
"toml::value::emplace_back(value): bad_cast to array type", {
|
"toml::value::emplace_back(...): ", this->type_, *this);
|
||||||
{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) ...);
|
this->as_array(std::nothrow).emplace_back(std::forward<Ts>(args) ...);
|
||||||
return this->as_array(std::nothrow).back();
|
return this->as_array(std::nothrow).back();
|
||||||
@@ -1655,15 +1654,15 @@ class basic_value
|
|||||||
{
|
{
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
return this->as_array().size();
|
return this->as_array(std::nothrow).size();
|
||||||
}
|
}
|
||||||
case value_t::table:
|
case value_t::table:
|
||||||
{
|
{
|
||||||
return this->as_table().size();
|
return this->as_table(std::nothrow).size();
|
||||||
}
|
}
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
return this->as_string().str.size();
|
return this->as_string(std::nothrow).str.size();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -1678,28 +1677,22 @@ class basic_value
|
|||||||
|
|
||||||
std::size_t count(const key_type& k) const
|
std::size_t count(const key_type& k) const
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::table)
|
if(!this->is_table())
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline(
|
detail::throw_bad_cast<value_t::table>(
|
||||||
"toml::value::count(key): bad_cast to table type", {
|
"toml::value::count(key): ", this->type_, *this);
|
||||||
{this->region_info_.get(),
|
|
||||||
concat_to_string("the actual type is ", this->type_)}
|
|
||||||
}), this->location());
|
|
||||||
}
|
}
|
||||||
return this->as_table().count(k);
|
return this->as_table(std::nothrow).count(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(const key_type& k) const
|
bool contains(const key_type& k) const
|
||||||
{
|
{
|
||||||
if(this->type_ != value_t::table)
|
if(!this->is_table())
|
||||||
{
|
{
|
||||||
throw type_error(detail::format_underline(
|
detail::throw_bad_cast<value_t::table>(
|
||||||
"toml::value::contains(key): bad_cast to table type", {
|
"toml::value::contains(key): ", this->type_, *this);
|
||||||
{this->region_info_.get(),
|
|
||||||
concat_to_string("the actual type is ", this->type_)}
|
|
||||||
}), this->location());
|
|
||||||
}
|
}
|
||||||
return (this->as_table().count(k) != 0);
|
return (this->as_table(std::nothrow).count(k) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
source_location location() const
|
source_location location() const
|
||||||
@@ -1724,13 +1717,11 @@ class basic_value
|
|||||||
}
|
}
|
||||||
|
|
||||||
// for error messages
|
// for error messages
|
||||||
template<typename C,
|
template<typename Value>
|
||||||
template<typename ...> class T, template<typename ...> class A>
|
friend region_base const& detail::get_region(const Value& v);
|
||||||
friend region_base const& detail::get_region(const basic_value<C, T, A>&);
|
|
||||||
|
|
||||||
template<typename Region, typename C,
|
template<typename Value, typename Region>
|
||||||
template<typename ...> class T, template<typename ...> class A>
|
friend void detail::change_region(Value& v, Region&& reg);
|
||||||
friend void detail::change_region(basic_value<C, T, A>&, Region&&);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -1760,30 +1751,6 @@ using value = basic_value<discard_comments, std::unordered_map, std::vector>;
|
|||||||
using array = typename value::array_type;
|
using array = typename value::array_type;
|
||||||
using table = typename value::table_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>
|
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||||
inline bool
|
inline bool
|
||||||
operator==(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
|
operator==(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
|
||||||
|
|||||||
Reference in New Issue
Block a user