mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
177 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c037913b2c | ||
|
|
6a328fe890 | ||
|
|
7c18cbb1d9 | ||
|
|
ba7d49f452 | ||
|
|
b0784ce286 | ||
|
|
670186fac7 | ||
|
|
5005998709 | ||
|
|
84fb703e04 | ||
|
|
8c2560761b | ||
|
|
07ea5e52e2 | ||
|
|
d2b1e962c9 | ||
|
|
528031012d | ||
|
|
c205c762fe | ||
|
|
a32cd6cb61 | ||
|
|
38e113d2dc | ||
|
|
f15480ae4d | ||
|
|
00bec8ae45 | ||
|
|
d599edd1d4 | ||
|
|
a9534579c6 | ||
|
|
c8ff302c94 | ||
|
|
003bc16c1b | ||
|
|
9132abc5c4 | ||
|
|
99d565bcc4 | ||
|
|
5f38127692 | ||
|
|
3c3ebd88b4 | ||
|
|
08f7ea9c56 | ||
|
|
cde29399f4 | ||
|
|
eec429e31b | ||
|
|
79ddcaece6 | ||
|
|
8398b9a08b | ||
|
|
9c5abf0bfd | ||
|
|
4fa94d45b3 | ||
|
|
46e84a9cc2 | ||
|
|
4e6ae9a994 | ||
|
|
f23c003d2f | ||
|
|
4b719f0806 | ||
|
|
22ace027de | ||
|
|
bc219af5b5 | ||
|
|
68e8a31659 | ||
|
|
32a5341d09 | ||
|
|
ce68f6f4c2 | ||
|
|
e696aabd11 | ||
|
|
7fb93e2f54 | ||
|
|
19cc9a2edf | ||
|
|
72f5afb6af | ||
|
|
a8fa14d159 | ||
|
|
75999aa9ad | ||
|
|
259da54edb | ||
|
|
b461f363da | ||
|
|
d43139a471 | ||
|
|
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 | ||
|
|
aa8d574dfe | ||
|
|
49fdb61731 | ||
|
|
b2bb21a473 | ||
|
|
0c58549fc6 | ||
|
|
b7b5e847d3 | ||
|
|
22d630fec1 | ||
|
|
f7bf341452 | ||
|
|
0934d90f90 | ||
|
|
f2c8d0e279 | ||
|
|
8c7d83d985 | ||
|
|
5ce44adbdc | ||
|
|
5c5b1320d0 | ||
|
|
8b737dc21f | ||
|
|
ee654b6c3f | ||
|
|
c59782d180 | ||
|
|
9bef715ccd | ||
|
|
d2b1cf5123 | ||
|
|
9f92916d1d | ||
|
|
666e4cf9dc | ||
|
|
cafee29c64 | ||
|
|
a7a2272b29 | ||
|
|
dc0bca2bb6 | ||
|
|
490abe04fd | ||
|
|
81ed4c0e9d | ||
|
|
1b07baf184 | ||
|
|
9073d52159 | ||
|
|
55260654bf | ||
|
|
aa6271af75 | ||
|
|
c54a03f189 | ||
|
|
c153c0e8c3 | ||
|
|
1f90af8e67 | ||
|
|
a0c5192b74 | ||
|
|
7f020f3f44 | ||
|
|
827b433389 | ||
|
|
b1827e6fca | ||
|
|
18f84088b4 | ||
|
|
c199bd8b49 | ||
|
|
5b35c1a74e | ||
|
|
d3513c0f84 | ||
|
|
1148d01c70 | ||
|
|
17d78553ff | ||
|
|
4c12dad51f |
@@ -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
|
||||||
|
|||||||
117
.github/workflows/main.yml
vendored
Normal file
117
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
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', '20']
|
||||||
|
exclude:
|
||||||
|
- {compiler: 'g++-5', standard: '17'}
|
||||||
|
- {compiler: 'g++-6', standard: '17'}
|
||||||
|
- {compiler: 'g++-5', standard: '20'}
|
||||||
|
- {compiler: 'g++-6', standard: '20'}
|
||||||
|
- {compiler: 'g++-7', standard: '20'}
|
||||||
|
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
|
||||||
|
if [[ "${{ matrix.compiler }}" == "g++-8" && ( "${{ matrix.standard }}" == "17" || "${{ matrix.standard }}" == "20" ) ]] ; then
|
||||||
|
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_REQUIRE_FILESYSTEM_LIBRARY=ON
|
||||||
|
else
|
||||||
|
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }}
|
||||||
|
fi
|
||||||
|
- 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', '20']
|
||||||
|
exclude:
|
||||||
|
- {compiler: '3.9', standard: '17'}
|
||||||
|
- {compiler: '4.0', standard: '17'}
|
||||||
|
- {compiler: '5.0', standard: '17'}
|
||||||
|
- {compiler: '3.9', standard: '20'}
|
||||||
|
- {compiler: '4.0', standard: '20'}
|
||||||
|
- {compiler: '5.0', standard: '20'}
|
||||||
|
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 .. -Dtoml11_BUILD_TEST=ON -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', '20']
|
||||||
|
config: ['Release', 'Debug']
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
- name: Configure
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
file --mime-encoding tests/test_literals.cpp
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ../ -G "NMake Makefiles" -Dtoml11_BUILD_TEST=ON -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: |
|
||||||
|
./tests/test_literals --log_level=all
|
||||||
|
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
|
||||||
153
.travis.yml
153
.travis.yml
@@ -5,7 +5,31 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
env: COMPILER="g++-5" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="g++-4.8" CXX_STANDARD=11
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
packages:
|
||||||
|
- g++-4.8
|
||||||
|
- boost1.70
|
||||||
|
- os: linux
|
||||||
|
language: cpp
|
||||||
|
compiler: gcc
|
||||||
|
env: COMPILER="g++-4.9" CXX_STANDARD=11
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
packages:
|
||||||
|
- g++-4.9
|
||||||
|
- boost1.70
|
||||||
|
- os: linux
|
||||||
|
language: cpp
|
||||||
|
compiler: gcc
|
||||||
|
env: COMPILER="g++-5" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -17,7 +41,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
env: COMPILER="g++-6" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="g++-6" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -29,7 +53,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
env: COMPILER="g++-7" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="g++-7" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -41,7 +65,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
env: COMPILER="g++-8" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="g++-8" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -65,7 +89,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
env: COMPILER="g++-8" CXX_STANDARD=17 TOML_HEAD=OFF
|
env: COMPILER="g++-8" CXX_STANDARD=14
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -77,7 +101,19 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
env: COMPILER="g++-8" CXX_STANDARD=17 TOML_HEAD=ON
|
env: COMPILER="g++-8" CXX_STANDARD=17 REQUIRE_FILESYSTEM_LIBRARY=ON
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
packages:
|
||||||
|
- g++-8
|
||||||
|
- boost1.70
|
||||||
|
- os: linux
|
||||||
|
language: cpp
|
||||||
|
compiler: gcc
|
||||||
|
env: COMPILER="g++-8" CXX_STANDARD=17 TOML_HEAD=ON REQUIRE_FILESYSTEM_LIBRARY=ON
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -89,7 +125,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-3.9" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="clang++-3.9" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -103,7 +139,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-4.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="clang++-4.0" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -117,7 +153,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-5.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="clang++-5.0" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -131,7 +167,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-6.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="clang++-6.0" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -145,7 +181,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-7" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="clang++-7" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -159,7 +195,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-8" CXX_STANDARD=11 TOML_HEAD=OFF
|
env: COMPILER="clang++-8" CXX_STANDARD=11
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -187,7 +223,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-8" CXX_STANDARD=17 TOML_HEAD=OFF
|
env: COMPILER="clang++-8" CXX_STANDARD=14
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -201,7 +237,49 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
language: cpp
|
language: cpp
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER="clang++-8" CXX_STANDARD=17 TOML_HEAD=ON
|
env: COMPILER="clang++-8" CXX_STANDARD=17 REQUIRE_FILESYSTEM_LIBRARY=ON
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-8
|
||||||
|
packages:
|
||||||
|
- clang-8
|
||||||
|
- g++-8
|
||||||
|
- boost1.70
|
||||||
|
- os: linux
|
||||||
|
language: cpp
|
||||||
|
compiler: clang
|
||||||
|
env: COMPILER="clang++-8" CXX_STANDARD=17 TOML_HEAD=ON REQUIRE_FILESYSTEM_LIBRARY=ON
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-8
|
||||||
|
packages:
|
||||||
|
- clang-8
|
||||||
|
- g++-8
|
||||||
|
- boost1.70
|
||||||
|
- os: linux
|
||||||
|
language: cpp
|
||||||
|
compiler: clang
|
||||||
|
env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_ASAN=ON
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||||
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
|
- llvm-toolchain-trusty-8
|
||||||
|
packages:
|
||||||
|
- clang-8
|
||||||
|
- g++-8
|
||||||
|
- boost1.70
|
||||||
|
- os: linux
|
||||||
|
language: cpp
|
||||||
|
compiler: clang
|
||||||
|
env: COMPILER="clang++-8" CXX_STANDARD=11 WITH_UBSAN=ON
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@@ -215,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:
|
||||||
- |
|
- |
|
||||||
@@ -234,17 +302,36 @@ 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
|
||||||
|
export TOML_HEAD="OFF"
|
||||||
|
fi
|
||||||
|
- echo "TOML_HEAD = ${TOML_HEAD}"
|
||||||
|
- |
|
||||||
|
if [[ "${WITH_ASAN}" != "ON" ]]; then
|
||||||
|
export WITH_ASAN="OFF"
|
||||||
|
fi
|
||||||
|
- echo "WITH_ASAN = ${WITH_ASAN}"
|
||||||
|
- |
|
||||||
|
if [[ "${WITH_UBSAN}" != "ON" ]]; then
|
||||||
|
export WITH_UBSAN="OFF"
|
||||||
|
fi
|
||||||
|
- echo "WITH_UBSAN = ${WITH_UBSAN}"
|
||||||
|
- echo "REQUIRE_FILESYSTEM_LIBRARY = ${REQUIRE_FILESYSTEM_LIBRARY}"
|
||||||
|
- |
|
||||||
|
if [[ "${REQUIRE_FILESYSTEM_LIBRARY}" != "ON" ]]; then
|
||||||
|
export REQUIRE_FILESYSTEM_LIBRARY="OFF"
|
||||||
|
fi
|
||||||
|
- echo "REQUIRE_FILESYSTEM_LIBRARY = ${REQUIRE_FILESYSTEM_LIBRARY}"
|
||||||
- cmake --version
|
- cmake --version
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd build
|
- cd build
|
||||||
- git clone https://github.com/toml-lang/toml.git
|
- echo "COMPILER = ${COMPILER}"
|
||||||
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} ..
|
- echo "CXX_STANDARD = ${CXX_STANDARD}"
|
||||||
|
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_REQUIRE_FILESYSTEM_LIBRARY=${REQUIRE_FILESYSTEM_LIBRARY} -Dtoml11_BUILD_TEST=ON -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,24 +1,17 @@
|
|||||||
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)
|
option(toml11_BUILD_TEST "Build toml tests" OFF)
|
||||||
set(toml11_VERSION_MINOR 2)
|
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
|
||||||
set(toml11_VERSION_PATCH 0)
|
option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF)
|
||||||
set(toml11_VERSION
|
|
||||||
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
|
||||||
)
|
|
||||||
|
|
||||||
option(toml11_BUILD_TEST "Build toml tests" ON)
|
|
||||||
|
|
||||||
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)
|
||||||
@@ -44,6 +37,11 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
add_definitions("/Zc:__cplusplus") # define __cplusplus value correctly
|
||||||
|
add_definitions("/utf-8") # enable to use u8"" literal
|
||||||
|
endif()
|
||||||
|
|
||||||
# Set some common directories
|
# Set some common directories
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
set(toml11_install_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/toml11)
|
set(toml11_install_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/toml11)
|
||||||
|
|||||||
232
README.md
232
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.2](https://toml.io/en/v1.0.0-rc.2).
|
||||||
[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;
|
||||||
}
|
}
|
||||||
@@ -84,7 +95,7 @@ int main()
|
|||||||
Just include the file after adding it to the include path.
|
Just include the file after adding it to the include path.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <toml11/toml.hpp> // that's all! now you can use it.
|
#include <toml.hpp> // that's all! now you can use it.
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@@ -99,6 +110,8 @@ int main()
|
|||||||
The convenient way is to add this repository as a git-submodule or to install
|
The convenient way is to add this repository as a git-submodule or to install
|
||||||
it in your system by CMake.
|
it in your system by CMake.
|
||||||
|
|
||||||
|
Note for MSVC: We recommend to set `/Zc:__cplusplus` to detect C++ version correctly.
|
||||||
|
|
||||||
## Decoding a toml file
|
## Decoding a toml file
|
||||||
|
|
||||||
To parse a toml file, the only thing you have to do is
|
To parse a toml file, the only thing you have to do is
|
||||||
@@ -109,6 +122,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 +272,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
|
||||||
@@ -274,10 +290,44 @@ const auto color = toml::find<std::string>(data, "fruit", "physical", "color");
|
|||||||
const auto shape = toml::find<std::string>(data, "fruit", "physical", "shape");
|
const auto shape = toml::find<std::string>(data, "fruit", "physical", "shape");
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Finding a value in an array
|
||||||
|
|
||||||
|
You can find n-th value in an array by `toml::find`.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
values = ["foo", "bar", "baz"]
|
||||||
|
```
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
const auto data = toml::parse("sample.toml");
|
||||||
|
const auto values = toml::find(data, "values");
|
||||||
|
const auto bar = toml::find<std::string>(values, 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
`toml::find` can also search array recursively.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const auto data = toml::parse("fruit.toml");
|
||||||
|
const auto bar = toml::find<std::string>(data, "values", 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
Before calling `toml::find`, you can check if a value corresponding to a key
|
||||||
|
exists. You can use both `bool toml::value::contains(const key&) const` and
|
||||||
|
`std::size_t toml::value::count(const key&) const`. Those behaves like the
|
||||||
|
`std::map::contains` and `std::map::count`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const auto data = toml::parse("fruit.toml");
|
||||||
|
if(data.contains("fruit") && data.at("fruit").count("physical") != 0)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### In case of error
|
### In case of error
|
||||||
|
|
||||||
If the value does not exist, `toml::find` throws an error with the location of
|
If the value does not exist, `toml::find` throws `std::out_of_range` with the
|
||||||
the table.
|
location of the table.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
terminate called after throwing an instance of 'std::out_of_range'
|
terminate called after throwing an instance of 'std::out_of_range'
|
||||||
@@ -287,11 +337,6 @@ terminate called after throwing an instance of 'std::out_of_range'
|
|||||||
| ~~~~~ in this table
|
| ~~~~~ in this table
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: It is recommended to find a table as `toml::value` because it has much information
|
|
||||||
compared to `toml::table`, which is an alias of
|
|
||||||
`std::unordered_map<std::string, toml::value>`. Since `toml::table` does not have
|
|
||||||
any information about toml file, such as where the table was defined in the file.
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
If the specified type differs from the actual value contained, it throws
|
If the specified type differs from the actual value contained, it throws
|
||||||
@@ -423,6 +468,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
|
||||||
@@ -869,14 +932,25 @@ toml::value v(toml::local_time(std::chrono::hours(10)));
|
|||||||
```
|
```
|
||||||
|
|
||||||
You can construct an array object not only from `initializer_list`, but also
|
You can construct an array object not only from `initializer_list`, but also
|
||||||
from STL containers.
|
from STL containers. In that case, the element type must be convertible to
|
||||||
|
`toml::value`.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::vector<int> vec{1,2,3,4,5};
|
std::vector<int> vec{1,2,3,4,5};
|
||||||
toml::value v = vec;
|
toml::value v(vec);
|
||||||
```
|
```
|
||||||
|
|
||||||
All the elements of `initializer_list` should be convertible into `toml::value`.
|
When you construct an array value, all the elements of `initializer_list`
|
||||||
|
must be convertible into `toml::value`.
|
||||||
|
|
||||||
|
If a `toml::value` has an array, you can `push_back` an element in it.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
toml::value v{1,2,3,4,5};
|
||||||
|
v.push_back(6);
|
||||||
|
```
|
||||||
|
|
||||||
|
`emplace_back` also works.
|
||||||
|
|
||||||
## Preserving comments
|
## Preserving comments
|
||||||
|
|
||||||
@@ -1093,7 +1167,7 @@ const auto data = toml::parse("example.toml");
|
|||||||
const foo f = toml::find<ext::foo>(data, "foo");
|
const foo f = toml::find<ext::foo>(data, "foo");
|
||||||
```
|
```
|
||||||
|
|
||||||
There are 2 ways to use `toml::get` with the types that you defined.
|
There are 3 ways to use `toml::get` with the types that you defined.
|
||||||
|
|
||||||
The first one is to implement `from_toml(const toml::value&)` member function.
|
The first one is to implement `from_toml(const toml::value&)` member function.
|
||||||
|
|
||||||
@@ -1120,7 +1194,31 @@ struct foo
|
|||||||
In this way, because `toml::get` first constructs `foo` without arguments,
|
In this way, because `toml::get` first constructs `foo` without arguments,
|
||||||
the type should be default-constructible.
|
the type should be default-constructible.
|
||||||
|
|
||||||
The second is to implement specialization of `toml::from` for your type.
|
The second is to implement `constructor(const toml::value&)`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace ext
|
||||||
|
{
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
explicit foo(const toml::value& v)
|
||||||
|
: a(toml::find<int>(v, "a")), b(toml::find<double>(v, "b")),
|
||||||
|
c(toml::find<std::string>(v, "c"))
|
||||||
|
{}
|
||||||
|
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
std::string c;
|
||||||
|
};
|
||||||
|
} // ext
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that implicit default constructor declaration will be suppressed
|
||||||
|
when a constructor is defined. If you want to use the struct (here, `foo`)
|
||||||
|
in a container (e.g. `std::vector<foo>`), you may need to define default
|
||||||
|
constructor explicitly.
|
||||||
|
|
||||||
|
The third is to implement specialization of `toml::from` for your type.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
namespace ext
|
namespace ext
|
||||||
@@ -1349,7 +1447,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
|
||||||
@@ -1376,6 +1474,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
|
||||||
@@ -1567,13 +1675,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`
|
||||||
@@ -1583,10 +1686,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
|
||||||
@@ -1595,8 +1698,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!
|
||||||
@@ -1604,6 +1709,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.
|
||||||
@@ -1632,15 +1748,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
|
||||||
@@ -1679,14 +1794,13 @@ 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 .. -Dtoml11_BUILD_TEST=ON
|
||||||
$ cmake ..
|
|
||||||
$ make
|
$ make
|
||||||
$ make test
|
$ make test
|
||||||
```
|
```
|
||||||
@@ -1719,11 +1833,27 @@ 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
|
||||||
|
- Scott McCaskill
|
||||||
|
- Parse 9 digits (nanoseconds) of fractional seconds in a `local_time`
|
||||||
|
- Shu Wang (@halfelf)
|
||||||
|
- fix "Finding a value in an array" example in README
|
||||||
|
- @maass-tv and @SeverinLeonhardt
|
||||||
|
- Fix MSVC warning C4866
|
||||||
|
- OGAWA KenIchi (@kenichiice)
|
||||||
|
- Fix include path in README
|
||||||
|
- Mohammed Alyousef (@MoAlyousef)
|
||||||
|
- Made testing optional in CMake
|
||||||
|
|
||||||
|
|
||||||
## Licensing terms
|
## Licensing terms
|
||||||
|
|
||||||
This product is licensed under the terms of the [MIT License](LICENSE).
|
This product is licensed under the terms of the [MIT License](LICENSE).
|
||||||
|
|
||||||
- Copyright (c) 2017-2019 Toru Niina
|
- Copyright (c) 2017-2020 Toru Niina
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|||||||
@@ -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
|
- cmake -G"%generator%" -DBOOST_ROOT=C:/Libraries/boost_1_69_0 -Dtoml11_BUILD_TEST=ON ..
|
||||||
- file --mime-encoding toml/tests/hard_example_unicode.toml
|
|
||||||
- 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
|
||||||
@@ -39,6 +48,17 @@ set(TEST_NAMES
|
|||||||
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
||||||
CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA)
|
CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA)
|
||||||
CHECK_CXX_COMPILER_FLAG("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
|
CHECK_CXX_COMPILER_FLAG("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Werror" COMPILER_SUPPORTS_WERROR)
|
||||||
|
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Wsign-conversion" COMPILER_SUPPORTS_WSIGN_CONVERSION)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Wconversion" COMPILER_SUPPORTS_WCONVERSION)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Wduplicated-cond" COMPILER_SUPPORTS_WDUPLICATED_COND)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
|
||||||
|
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")
|
||||||
@@ -49,6 +69,36 @@ endif()
|
|||||||
if(COMPILER_SUPPORTS_WPEDANTIC)
|
if(COMPILER_SUPPORTS_WPEDANTIC)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||||
endif()
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WERROR)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||||
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WSIGN_CONVERSION)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
|
||||||
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WCONVERSION)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
|
||||||
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WDUPLICATED_COND)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-cond")
|
||||||
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-branches")
|
||||||
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WLOGICAL_OP)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wlogical-op")
|
||||||
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WUSELESS_CAST)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wuseless-cast")
|
||||||
|
endif()
|
||||||
|
if(COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
|
||||||
|
endif()
|
||||||
|
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)
|
||||||
@@ -100,11 +150,61 @@ find_package(Boost COMPONENTS unit_test_framework REQUIRED)
|
|||||||
add_definitions(-DBOOST_TEST_DYN_LINK)
|
add_definitions(-DBOOST_TEST_DYN_LINK)
|
||||||
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
|
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
|
||||||
|
|
||||||
|
# check which standard library implementation is used. If libstdc++ is used,
|
||||||
|
# it will fail to compile. It compiles if libc++ is used.
|
||||||
|
include(CheckCXXSourceCompiles)
|
||||||
|
check_cxx_source_compiles("
|
||||||
|
#include <cstddef>
|
||||||
|
#ifdef __GLIBCXX__
|
||||||
|
static_assert(false);
|
||||||
|
#endif
|
||||||
|
int main() {
|
||||||
|
return 0;
|
||||||
|
}" TOML11_WITH_LIBCXX_LIBRARY)
|
||||||
|
|
||||||
|
# LLVM 8 requires -lc++fs if compiled with libc++ to use <filesystem>.
|
||||||
|
# LLVM 9+ does not require any special library.
|
||||||
|
# GCC 8 requires -lstdc++fs. GCC 9+ does not require it.
|
||||||
|
#
|
||||||
|
# Yes, we can check the version of the compiler used in the current build
|
||||||
|
# directly in CMake. But, in most cases, clang build uses libstdc++ as the
|
||||||
|
# standard library implementation and it makes the condition complicated.
|
||||||
|
# In many environment, the default installed C++ compiler is GCC and libstdc++
|
||||||
|
# is installed along with it. In most build on such an environment, even if we
|
||||||
|
# chose clang as the C++ compiler, still libstdc++ is used. Checking default
|
||||||
|
# gcc version makes the condition complicated.
|
||||||
|
# The purpose of this file is to compile tests. We know the environment on which
|
||||||
|
# the tests run. We can set this option and, I think, it is easier and better.
|
||||||
|
option(TOML11_REQUIRE_FILESYSTEM_LIBRARY "need to link -lstdc++fs or -lc++fs" OFF)
|
||||||
|
|
||||||
foreach(TEST_NAME ${TEST_NAMES})
|
foreach(TEST_NAME ${TEST_NAMES})
|
||||||
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
|
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
|
||||||
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
|
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
|
||||||
|
|
||||||
|
# to compile tests with <filesystem>...
|
||||||
|
if(TOML11_REQUIRE_FILESYSTEM_LIBRARY)
|
||||||
|
if(TOML11_WITH_LIBCXX_LIBRARY)
|
||||||
|
target_link_libraries(${TEST_NAME} "c++fs")
|
||||||
|
else()
|
||||||
|
target_link_libraries(${TEST_NAME} "stdc++fs")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
|
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
if(toml11_TEST_WITH_ASAN)
|
||||||
|
set_target_properties(${TEST_NAME} PROPERTIES
|
||||||
|
COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer"
|
||||||
|
LINK_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
|
||||||
|
elseif(toml11_TEST_WITH_UBSAN)
|
||||||
|
set_target_properties(${TEST_NAME} PROPERTIES
|
||||||
|
COMPILE_FLAGS "-fsanitize=undefined"
|
||||||
|
LINK_FLAGS "-fsanitize=undefined")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${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)
|
||||||
@@ -115,8 +215,15 @@ foreach(TEST_NAME ${TEST_NAMES})
|
|||||||
endif()
|
endif()
|
||||||
endforeach(TEST_NAME)
|
endforeach(TEST_NAME)
|
||||||
|
|
||||||
|
|
||||||
# this test is to check it compiles. it will not run
|
# this test is to check it compiles. it will not run
|
||||||
add_executable(test_multiple_translation_unit
|
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()
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
BOOST_AUTO_TEST_CASE(test_comment_before)
|
BOOST_AUTO_TEST_CASE(test_comment_before)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
const std::string file = u8R"(
|
const std::string file = R"(
|
||||||
# comment for a.
|
# comment for a.
|
||||||
a = 42
|
a = 42
|
||||||
# comment for b.
|
# comment for b.
|
||||||
@@ -24,12 +24,12 @@ BOOST_AUTO_TEST_CASE(test_comment_before)
|
|||||||
const auto& b = toml::find(v, "b");
|
const auto& b = toml::find(v, "b");
|
||||||
|
|
||||||
BOOST_TEST(a.comments().size() == 1u);
|
BOOST_TEST(a.comments().size() == 1u);
|
||||||
BOOST_TEST(a.comments().front() == u8" comment for a.");
|
BOOST_TEST(a.comments().front() == " comment for a.");
|
||||||
BOOST_TEST(b.comments().size() == 1u);
|
BOOST_TEST(b.comments().size() == 1u);
|
||||||
BOOST_TEST(b.comments().front() == u8" comment for b.");
|
BOOST_TEST(b.comments().front() == " comment for b.");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const std::string file = u8R"(
|
const std::string file = R"(
|
||||||
# comment for a.
|
# comment for a.
|
||||||
# another comment for a.
|
# another comment for a.
|
||||||
a = 42
|
a = 42
|
||||||
@@ -45,18 +45,18 @@ BOOST_AUTO_TEST_CASE(test_comment_before)
|
|||||||
const auto& b = toml::find(v, "b");
|
const auto& b = toml::find(v, "b");
|
||||||
|
|
||||||
BOOST_TEST(a.comments().size() == 2u);
|
BOOST_TEST(a.comments().size() == 2u);
|
||||||
BOOST_TEST(a.comments().front() == u8" comment for a.");
|
BOOST_TEST(a.comments().front() == " comment for a.");
|
||||||
BOOST_TEST(a.comments().back() == u8" another comment for a.");
|
BOOST_TEST(a.comments().back() == " another comment for a.");
|
||||||
BOOST_TEST(b.comments().size() == 2u);
|
BOOST_TEST(b.comments().size() == 2u);
|
||||||
BOOST_TEST(b.comments().front() == u8" comment for b.");
|
BOOST_TEST(b.comments().front() == " comment for b.");
|
||||||
BOOST_TEST(b.comments().back() == u8" also comment for b.");
|
BOOST_TEST(b.comments().back() == " also comment for b.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_comment_inline)
|
BOOST_AUTO_TEST_CASE(test_comment_inline)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
const std::string file = u8R"(
|
const std::string file = R"(
|
||||||
a = 42 # comment for a.
|
a = 42 # comment for a.
|
||||||
b = "baz" # comment for b.
|
b = "baz" # comment for b.
|
||||||
)";
|
)";
|
||||||
@@ -68,12 +68,12 @@ BOOST_AUTO_TEST_CASE(test_comment_inline)
|
|||||||
const auto& b = toml::find(v, "b");
|
const auto& b = toml::find(v, "b");
|
||||||
|
|
||||||
BOOST_TEST(a.comments().size() == 1u);
|
BOOST_TEST(a.comments().size() == 1u);
|
||||||
BOOST_TEST(a.comments().front() == u8" comment for a.");
|
BOOST_TEST(a.comments().front() == " comment for a.");
|
||||||
BOOST_TEST(b.comments().size() == 1u);
|
BOOST_TEST(b.comments().size() == 1u);
|
||||||
BOOST_TEST(b.comments().front() == u8" comment for b.");
|
BOOST_TEST(b.comments().front() == " comment for b.");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const std::string file = u8R"(
|
const std::string file = R"(
|
||||||
a = [
|
a = [
|
||||||
42,
|
42,
|
||||||
] # comment for a.
|
] # comment for a.
|
||||||
@@ -90,18 +90,18 @@ BOOST_AUTO_TEST_CASE(test_comment_inline)
|
|||||||
const auto& b0 = b.as_array().at(0);
|
const auto& b0 = b.as_array().at(0);
|
||||||
|
|
||||||
BOOST_TEST(a.comments().size() == 1u);
|
BOOST_TEST(a.comments().size() == 1u);
|
||||||
BOOST_TEST(a.comments().front() == u8" comment for a.");
|
BOOST_TEST(a.comments().front() == " comment for a.");
|
||||||
BOOST_TEST(b.comments().size() == 1u);
|
BOOST_TEST(b.comments().size() == 1u);
|
||||||
BOOST_TEST(b.comments().front() == u8" this is a comment for b.");
|
BOOST_TEST(b.comments().front() == " this is a comment for b.");
|
||||||
BOOST_TEST(b0.comments().size() == 1u);
|
BOOST_TEST(b0.comments().size() == 1u);
|
||||||
BOOST_TEST(b0.comments().front() == u8" this is not a comment for b, but \"bar\"");
|
BOOST_TEST(b0.comments().front() == " this is not a comment for b, but \"bar\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_comment_both)
|
BOOST_AUTO_TEST_CASE(test_comment_both)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
const std::string file = u8R"(
|
const std::string file = R"(
|
||||||
# comment for a.
|
# comment for a.
|
||||||
a = 42 # inline comment for a.
|
a = 42 # inline comment for a.
|
||||||
# comment for b.
|
# comment for b.
|
||||||
@@ -122,25 +122,25 @@ BOOST_AUTO_TEST_CASE(test_comment_both)
|
|||||||
const auto& c0 = c.as_array().at(0);
|
const auto& c0 = c.as_array().at(0);
|
||||||
|
|
||||||
BOOST_TEST(a.comments().size() == 2u);
|
BOOST_TEST(a.comments().size() == 2u);
|
||||||
BOOST_TEST(a.comments().front() == u8" comment for a.");
|
BOOST_TEST(a.comments().front() == " comment for a.");
|
||||||
BOOST_TEST(a.comments().back() == u8" inline comment for a.");
|
BOOST_TEST(a.comments().back() == " inline comment for a.");
|
||||||
BOOST_TEST(b.comments().size() == 2u);
|
BOOST_TEST(b.comments().size() == 2u);
|
||||||
BOOST_TEST(b.comments().front() == u8" comment for b.");
|
BOOST_TEST(b.comments().front() == " comment for b.");
|
||||||
BOOST_TEST(b.comments().back() == u8" inline comment for b.");
|
BOOST_TEST(b.comments().back() == " inline comment for b.");
|
||||||
|
|
||||||
BOOST_TEST(c.comments().size() == 2u);
|
BOOST_TEST(c.comments().size() == 2u);
|
||||||
BOOST_TEST(c.comments().front() == u8" comment for c.");
|
BOOST_TEST(c.comments().front() == " comment for c.");
|
||||||
BOOST_TEST(c.comments().back() == u8" another comment for c.");
|
BOOST_TEST(c.comments().back() == " another comment for c.");
|
||||||
|
|
||||||
BOOST_TEST(c0.comments().size() == 2u);
|
BOOST_TEST(c0.comments().size() == 2u);
|
||||||
BOOST_TEST(c0.comments().front() == u8" comment for the first element.");
|
BOOST_TEST(c0.comments().front() == " comment for the first element.");
|
||||||
BOOST_TEST(c0.comments().back() == u8" this also.");
|
BOOST_TEST(c0.comments().back() == " this also.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_discard_comment)
|
BOOST_AUTO_TEST_CASE(test_discard_comment)
|
||||||
{
|
{
|
||||||
const std::string file = u8R"(
|
const std::string file = R"(
|
||||||
# comment for a.
|
# comment for a.
|
||||||
a = 42 # inline comment for a.
|
a = 42 # inline comment for a.
|
||||||
# comment for b.
|
# comment for b.
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,16 @@ struct qux
|
|||||||
int a;
|
int a;
|
||||||
std::string b;
|
std::string b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct foobar
|
||||||
|
{
|
||||||
|
// via constructor
|
||||||
|
explicit foobar(const toml::value& v)
|
||||||
|
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
|
||||||
|
{}
|
||||||
|
int a;
|
||||||
|
std::string b;
|
||||||
|
};
|
||||||
} // extlib
|
} // extlib
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
@@ -122,6 +132,17 @@ struct qux
|
|||||||
int a;
|
int a;
|
||||||
std::string b;
|
std::string b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct foobar
|
||||||
|
{
|
||||||
|
template<typename C, template<typename ...> class M, template<typename ...> class A>
|
||||||
|
explicit foobar(const toml::basic_value<C, M, A>& v)
|
||||||
|
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
|
||||||
|
{}
|
||||||
|
int a;
|
||||||
|
std::string b;
|
||||||
|
};
|
||||||
|
|
||||||
} // extlib2
|
} // extlib2
|
||||||
|
|
||||||
namespace toml
|
namespace toml
|
||||||
@@ -284,6 +305,27 @@ BOOST_AUTO_TEST_CASE(test_conversion_one_way)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_conversion_via_constructor)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const toml::value v{{"a", 42}, {"b", "foobar"}};
|
||||||
|
|
||||||
|
const auto foobar = toml::get<extlib::foobar>(v);
|
||||||
|
BOOST_TEST(foobar.a == 42);
|
||||||
|
BOOST_TEST(foobar.b == "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const toml::basic_value<toml::discard_comments, std::map> v{
|
||||||
|
{"a", 42}, {"b", "foobar"}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto foobar = toml::get<extlib2::foobar>(v);
|
||||||
|
BOOST_TEST(foobar.a == 42);
|
||||||
|
BOOST_TEST(foobar.b == "foobar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -384,5 +426,122 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
|||||||
BOOST_TEST(bars.at(2).b == "quux");
|
BOOST_TEST(bars.at(2).b == "quux");
|
||||||
BOOST_TEST(bars.at(3).b == "foobar");
|
BOOST_TEST(bars.at(3).b == "foobar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// via constructor
|
||||||
|
{
|
||||||
|
const toml::value v{
|
||||||
|
toml::table{{"a", 42}, {"b", "baz"}},
|
||||||
|
toml::table{{"a", 43}, {"b", "qux"}},
|
||||||
|
toml::table{{"a", 44}, {"b", "quux"}},
|
||||||
|
toml::table{{"a", 45}, {"b", "foobar"}}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto foobars = toml::get<std::vector<extlib::foobar>>(v);
|
||||||
|
BOOST_TEST(foobars.size() == 4ul);
|
||||||
|
BOOST_TEST(foobars.at(0).a == 42);
|
||||||
|
BOOST_TEST(foobars.at(1).a == 43);
|
||||||
|
BOOST_TEST(foobars.at(2).a == 44);
|
||||||
|
BOOST_TEST(foobars.at(3).a == 45);
|
||||||
|
|
||||||
|
BOOST_TEST(foobars.at(0).b == "baz");
|
||||||
|
BOOST_TEST(foobars.at(1).b == "qux");
|
||||||
|
BOOST_TEST(foobars.at(2).b == "quux");
|
||||||
|
BOOST_TEST(foobars.at(3).b == "foobar");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
|
||||||
|
BOOST_TEST(foobars.size() == 4ul);
|
||||||
|
BOOST_TEST(foobars.at(0).a == 42);
|
||||||
|
BOOST_TEST(foobars.at(1).a == 43);
|
||||||
|
BOOST_TEST(foobars.at(2).a == 44);
|
||||||
|
BOOST_TEST(foobars.at(3).a == 45);
|
||||||
|
|
||||||
|
BOOST_TEST(foobars.at(0).b == "baz");
|
||||||
|
BOOST_TEST(foobars.at(1).b == "qux");
|
||||||
|
BOOST_TEST(foobars.at(2).b == "quux");
|
||||||
|
BOOST_TEST(foobars.at(3).b == "foobar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||||
|
v{
|
||||||
|
toml::table{{"a", 42}, {"b", "baz"}},
|
||||||
|
toml::table{{"a", 43}, {"b", "qux"}},
|
||||||
|
toml::table{{"a", 44}, {"b", "quux"}},
|
||||||
|
toml::table{{"a", 45}, {"b", "foobar"}}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
|
||||||
|
BOOST_TEST(foobars.size() == 4ul);
|
||||||
|
BOOST_TEST(foobars.at(0).a == 42);
|
||||||
|
BOOST_TEST(foobars.at(1).a == 43);
|
||||||
|
BOOST_TEST(foobars.at(2).a == 44);
|
||||||
|
BOOST_TEST(foobars.at(3).a == 45);
|
||||||
|
|
||||||
|
BOOST_TEST(foobars.at(0).b == "baz");
|
||||||
|
BOOST_TEST(foobars.at(1).b == "qux");
|
||||||
|
BOOST_TEST(foobars.at(2).b == "quux");
|
||||||
|
BOOST_TEST(foobars.at(3).b == "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,78 @@ BOOST_AUTO_TEST_CASE(test_find_throws)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_find_array_throws)
|
||||||
|
{
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// const-reference version
|
||||||
|
{
|
||||||
|
// value is not an array
|
||||||
|
const toml::value v(true);
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the value corresponding to the key is not the expected type
|
||||||
|
const toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the value corresponding to the key is not found
|
||||||
|
const toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the positive control.
|
||||||
|
const toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_TEST(3 == toml::find<int>(v, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// non-const reference version
|
||||||
|
{
|
||||||
|
// value is not an array
|
||||||
|
toml::value v(true);
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the value corresponding to the key is not the expected type
|
||||||
|
toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the value corresponding to the key is not found
|
||||||
|
toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the positive control.
|
||||||
|
toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_TEST(3 == toml::find<int>(v, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// move version
|
||||||
|
{
|
||||||
|
// value is not an array
|
||||||
|
toml::value v(true);
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the value corresponding to the key is not the expected type
|
||||||
|
toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the value corresponding to the key is not found
|
||||||
|
toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_CHECK_THROW(toml::find<toml::integer>(std::move(v), 6), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// the positive control.
|
||||||
|
toml::value v{1, 2, 3, 4, 5};
|
||||||
|
BOOST_TEST(3 == toml::find<int>(std::move(v), 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_find_recursive)
|
BOOST_AUTO_TEST_CASE(test_find_recursive)
|
||||||
{
|
{
|
||||||
// recursively search tables
|
// recursively search tables
|
||||||
@@ -126,8 +198,76 @@ BOOST_AUTO_TEST_CASE(test_find_recursive)
|
|||||||
num2 = 42;
|
num2 = 42;
|
||||||
BOOST_TEST(42 == toml::find<int>(v, a, b, c, d));
|
BOOST_TEST(42 == toml::find<int>(v, a, b, c, d));
|
||||||
|
|
||||||
auto num3 = toml::find<toml::integer>(std::move(v), a, b, c, d);
|
auto num3 = toml::find<toml::integer>(v, a, "b", c, "d");
|
||||||
BOOST_TEST(42 == num3);
|
BOOST_TEST(42 == num3);
|
||||||
|
|
||||||
|
auto num4 = toml::find<toml::integer>(std::move(v), a, b, c, d);
|
||||||
|
BOOST_TEST(42 == num4);
|
||||||
|
}
|
||||||
|
// recursively search arrays
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
toml::array{"array", "of", "string"},
|
||||||
|
toml::array{toml::array{1, 2, 3}, toml::array{3.14, 2.71}}
|
||||||
|
};
|
||||||
|
BOOST_TEST("array" == toml::find<std::string>(v, 0, 0));
|
||||||
|
BOOST_TEST("of" == toml::find<std::string>(v, 0, 1));
|
||||||
|
BOOST_TEST("string" == toml::find<std::string>(v, 0, 2));
|
||||||
|
|
||||||
|
BOOST_TEST(1 == toml::find<int>(v, 1, 0, 0));
|
||||||
|
BOOST_TEST(2 == toml::find<int>(v, 1, 0, 1));
|
||||||
|
BOOST_TEST(3 == toml::find<int>(v, 1, 0, 2));
|
||||||
|
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, 1, 1, 0));
|
||||||
|
BOOST_TEST(2.71 == toml::find<double>(v, 1, 1, 1));
|
||||||
|
|
||||||
|
// reference that can be used to modify the content
|
||||||
|
auto& num = toml::find<toml::integer>(v, 1, 0, 2);
|
||||||
|
num = 42;
|
||||||
|
BOOST_TEST( 1 == toml::find<int>(v, 1, 0, 0));
|
||||||
|
BOOST_TEST( 2 == toml::find<int>(v, 1, 0, 1));
|
||||||
|
BOOST_TEST(42 == toml::find<int>(v, 1, 0, 2));
|
||||||
|
|
||||||
|
// move value
|
||||||
|
auto num2 = toml::find<toml::integer>(std::move(v), 1, 0, 2);
|
||||||
|
BOOST_TEST(42 == num2);
|
||||||
|
}
|
||||||
|
// recursively search mixtures
|
||||||
|
{
|
||||||
|
toml::value v = toml::table{{"array", toml::array{
|
||||||
|
toml::array{1, 2, 3},
|
||||||
|
toml::array{
|
||||||
|
toml::table{{"foo", "bar"}, {"baz", "qux"}},
|
||||||
|
toml::table{{"pi", 3.14}, {"e", 2.71}}
|
||||||
|
}}
|
||||||
|
}};
|
||||||
|
|
||||||
|
BOOST_TEST(1 == toml::find<int>(v, "array", 0, 0));
|
||||||
|
BOOST_TEST(2 == toml::find<int>(v, "array", 0, 1));
|
||||||
|
BOOST_TEST(3 == toml::find<int>(v, "array", 0, 2));
|
||||||
|
|
||||||
|
BOOST_TEST("bar" == toml::find<std::string>(v, "array", 1, 0, "foo"));
|
||||||
|
BOOST_TEST("qux" == toml::find<std::string>(v, "array", 1, 0, "baz"));
|
||||||
|
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, "pi"));
|
||||||
|
BOOST_TEST(2.71 == toml::find<double>(v, "array", 1, 1, "e"));
|
||||||
|
|
||||||
|
const std::string ar("array");
|
||||||
|
const auto ar_c = "array";
|
||||||
|
|
||||||
|
const std::string pi("pi");
|
||||||
|
const auto pi_c = "pi";
|
||||||
|
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, "pi"));
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi));
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi_c));
|
||||||
|
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, "pi"));
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi));
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi_c));
|
||||||
|
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi));
|
||||||
|
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi_c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,10 +449,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_floating_type, value_type, test_value_ty
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
value_type v{{"key", 3.14}};
|
value_type v{{"key", 3.14}};
|
||||||
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(v, "key"));
|
const double ref(3.14);
|
||||||
BOOST_TEST(static_cast<double >(3.14) == toml::find<double >(v, "key"));
|
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(v, "key"));
|
||||||
BOOST_TEST(static_cast<long double>(3.14) == toml::find<long double>(v, "key"));
|
BOOST_TEST( ref == toml::find<double >(v, "key"));
|
||||||
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(std::move(v), "key"));
|
BOOST_TEST(static_cast<long double>(ref) == toml::find<long double>(v, "key"));
|
||||||
|
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(std::move(v), "key"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,14 +514,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array, value_type, test_value_types
|
|||||||
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
||||||
|
|
||||||
std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key");
|
std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key");
|
||||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
BOOST_TEST(42 == ary.at(0));
|
||||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
BOOST_TEST(54 == ary.at(1));
|
||||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
BOOST_TEST(69 == ary.at(2));
|
||||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
BOOST_TEST(72 == ary.at(3));
|
||||||
|
|
||||||
std::tuple<int, short, unsigned, long> tpl =
|
std::tuple<int, short, unsigned, long> tpl =
|
||||||
toml::find<std::tuple<int, short, unsigned, long>>(v, "key");
|
toml::find<std::tuple<int, short, unsigned, long>>(v, "key");
|
||||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||||
@@ -420,14 +561,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_move_toml_array, value_type, test_value_
|
|||||||
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
||||||
|
|
||||||
std::array<int, 4> ary = toml::find<std::array<int, 4>>(std::move(v4), "key");
|
std::array<int, 4> ary = toml::find<std::array<int, 4>>(std::move(v4), "key");
|
||||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
BOOST_TEST(42 == ary.at(0));
|
||||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
BOOST_TEST(54 == ary.at(1));
|
||||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
BOOST_TEST(69 == ary.at(2));
|
||||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
BOOST_TEST(72 == ary.at(3));
|
||||||
|
|
||||||
std::tuple<int, short, unsigned, long> tpl =
|
std::tuple<int, short, unsigned, long> tpl =
|
||||||
toml::find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key");
|
toml::find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key");
|
||||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||||
|
|||||||
@@ -375,7 +375,8 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
|
|||||||
toml::value v1{{"key", 42}};
|
toml::value v1{{"key", 42}};
|
||||||
toml::value v2{{"key", 3.14}};
|
toml::value v2{{"key", 3.14}};
|
||||||
BOOST_TEST(2.71f == toml::find_or(v1, "key", 2.71f));
|
BOOST_TEST(2.71f == toml::find_or(v1, "key", 2.71f));
|
||||||
BOOST_TEST(static_cast<float>(double(3.14)) == toml::find_or(v2, "key", 2.71f));
|
const double ref(3.14);
|
||||||
|
BOOST_TEST(static_cast<float>(ref) == toml::find_or(v2, "key", 2.71f));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
toml::value v1{{"key", 42}};
|
toml::value v1{{"key", 42}};
|
||||||
@@ -383,7 +384,8 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
|
|||||||
const auto moved1 = toml::find_or(std::move(v1), "key", 2.71f);
|
const auto moved1 = toml::find_or(std::move(v1), "key", 2.71f);
|
||||||
const auto moved2 = toml::find_or(std::move(v2), "key", 2.71f);
|
const auto moved2 = toml::find_or(std::move(v2), "key", 2.71f);
|
||||||
BOOST_TEST(2.71f == moved1);
|
BOOST_TEST(2.71f == moved1);
|
||||||
BOOST_TEST(static_cast<float>(double(3.14)) == moved2);
|
const double ref(3.14);
|
||||||
|
BOOST_TEST(static_cast<float>(ref) == moved2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -195,11 +195,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_floating_type, value_type, test_value_typ
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
value_type v(3.14);
|
value_type v(3.14);
|
||||||
BOOST_TEST(static_cast<float >(3.14) == toml::get<float >(v));
|
const double ref(3.14);
|
||||||
BOOST_TEST(static_cast<double >(3.14) == toml::get<double >(v));
|
BOOST_TEST(static_cast<float >(ref) == toml::get<float >(v));
|
||||||
BOOST_TEST(static_cast<long double>(3.14) == toml::get<long double>(v));
|
BOOST_TEST( ref == toml::get<double >(v));
|
||||||
|
BOOST_TEST(static_cast<long double>(ref) == toml::get<long double>(v));
|
||||||
BOOST_TEST(3.14f == toml::get<float>(std::move(v)));
|
BOOST_TEST(static_cast<float >(ref) == toml::get<float>(std::move(v)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,14 +262,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
|
|||||||
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
||||||
|
|
||||||
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
|
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
|
||||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
BOOST_TEST(42 == ary.at(0));
|
||||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
BOOST_TEST(54 == ary.at(1));
|
||||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
BOOST_TEST(69 == ary.at(2));
|
||||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
BOOST_TEST(72 == ary.at(3));
|
||||||
|
|
||||||
std::tuple<int, short, unsigned, long> tpl =
|
std::tuple<int, short, unsigned, long> tpl =
|
||||||
toml::get<std::tuple<int, short, unsigned, long>>(v);
|
toml::get<std::tuple<int, short, unsigned, long>>(v);
|
||||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||||
@@ -308,16 +308,16 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
|
|||||||
{
|
{
|
||||||
value_type v{42, 54, 69, 72};
|
value_type v{42, 54, 69, 72};
|
||||||
std::array<int, 4> ary = toml::get<std::array<int, 4>>(std::move(v));
|
std::array<int, 4> ary = toml::get<std::array<int, 4>>(std::move(v));
|
||||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
BOOST_TEST(42 == ary.at(0));
|
||||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
BOOST_TEST(54 == ary.at(1));
|
||||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
BOOST_TEST(69 == ary.at(2));
|
||||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
BOOST_TEST(72 == ary.at(3));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
value_type v{42, 54, 69, 72};
|
value_type v{42, 54, 69, 72};
|
||||||
std::tuple<int, short, unsigned, long> tpl =
|
std::tuple<int, short, unsigned, long> tpl =
|
||||||
toml::get<std::tuple<int, short, unsigned, long>>(std::move(v));
|
toml::get<std::tuple<int, short, unsigned, long>>(std::move(v));
|
||||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
do { \
|
do { \
|
||||||
const std::string token (tkn); \
|
const std::string token (tkn); \
|
||||||
const std::string expected(expct); \
|
const std::string expected(expct); \
|
||||||
toml::detail::location<std::string> loc("test", token); \
|
toml::detail::location loc("test", token); \
|
||||||
const auto result = lxr::invoke(loc); \
|
const auto result = lxr::invoke(loc); \
|
||||||
BOOST_TEST(result.is_ok()); \
|
BOOST_TEST(result.is_ok()); \
|
||||||
if(result.is_ok()){ \
|
if(result.is_ok()){ \
|
||||||
@@ -28,7 +28,7 @@ do { \
|
|||||||
#define TOML11_TEST_LEX_REJECT(lxr, tkn) \
|
#define TOML11_TEST_LEX_REJECT(lxr, tkn) \
|
||||||
do { \
|
do { \
|
||||||
const std::string token (tkn); \
|
const std::string token (tkn); \
|
||||||
toml::detail::location<std::string> loc("test", token); \
|
toml::detail::location loc("test", token); \
|
||||||
const auto result = lxr::invoke(loc); \
|
const auto result = lxr::invoke(loc); \
|
||||||
BOOST_TEST(result.is_err()); \
|
BOOST_TEST(result.is_err()); \
|
||||||
const bool loc_same = (loc.begin() == loc.iter()); \
|
const bool loc_same = (loc.begin() == loc.iter()); \
|
||||||
|
|||||||
@@ -18,12 +18,11 @@ BOOST_AUTO_TEST_CASE(test_quoted_key)
|
|||||||
{
|
{
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_key, "\"127.0.0.1\"", "\"127.0.0.1\"");
|
TOML11_TEST_LEX_ACCEPT(lex_key, "\"127.0.0.1\"", "\"127.0.0.1\"");
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_key, "\"character encoding\"", "\"character encoding\"");
|
TOML11_TEST_LEX_ACCEPT(lex_key, "\"character encoding\"", "\"character encoding\"");
|
||||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
|
||||||
|
// UTF-8 codepoint of characters that looks like "key" written upside down
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"",
|
TOML11_TEST_LEX_ACCEPT(lex_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"",
|
||||||
"\"\xCA\x8E\xC7\x9D\xCA\x9E\"");
|
"\"\xCA\x8E\xC7\x9D\xCA\x9E\"");
|
||||||
#else
|
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_key, u8"\"ʎǝʞ\"", u8"\"ʎǝʞ\"");
|
|
||||||
#endif
|
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_key, "'key2'", "'key2'");
|
TOML11_TEST_LEX_ACCEPT(lex_key, "'key2'", "'key2'");
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_key, "'quoted \"value\"'", "'quoted \"value\"'");
|
TOML11_TEST_LEX_ACCEPT(lex_key, "'quoted \"value\"'", "'quoted \"value\"'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,15 +31,9 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
|
|||||||
"\"192.168.1.1\"",
|
"\"192.168.1.1\"",
|
||||||
"\"192.168.1.1\"");
|
"\"192.168.1.1\"");
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"",
|
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"", // UTF-8 string (means "China" in
|
||||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"");
|
"\"\xE4\xB8\xAD\xE5\x9B\xBD\""); // Chinese characters)
|
||||||
#else
|
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
|
||||||
u8"\"中国\"",
|
|
||||||
u8"\"中国\"");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||||
"\"You'll hate me after this - #\"",
|
"\"You'll hate me after this - #\"",
|
||||||
@@ -57,6 +51,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 +93,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.''''");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,170 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
|
|||||||
{
|
{
|
||||||
using namespace toml::literals::toml_literals;
|
using namespace toml::literals::toml_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
const toml::value r{{"a", 42}, {"b", "baz"}};
|
||||||
|
const toml::value v = R"(
|
||||||
|
a = 42
|
||||||
|
b = "baz"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(r == v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value r{
|
||||||
|
{"c", 3.14},
|
||||||
|
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
|
||||||
|
};
|
||||||
|
const toml::value v = R"(
|
||||||
|
c = 3.14
|
||||||
|
[table]
|
||||||
|
a = 42
|
||||||
|
b = "baz"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(r == v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value r{
|
||||||
|
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
|
||||||
|
};
|
||||||
|
const toml::value v = R"(
|
||||||
|
[table]
|
||||||
|
a = 42
|
||||||
|
b = "baz"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(r == v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value r{
|
||||||
|
{"array_of_tables", toml::array{toml::table{}}}
|
||||||
|
};
|
||||||
|
const toml::value v = R"(
|
||||||
|
[[array_of_tables]]
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(r == v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
||||||
|
{
|
||||||
|
using namespace toml::literals::toml_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
const toml::value v1 = "true"_toml;
|
||||||
|
const toml::value v2 = "false"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_boolean());
|
||||||
|
BOOST_TEST(v2.is_boolean());
|
||||||
|
BOOST_TEST(toml::get<bool>(v1));
|
||||||
|
BOOST_TEST(!toml::get<bool>(v2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = "123_456"_toml;
|
||||||
|
const toml::value v2 = "0b0010"_toml;
|
||||||
|
const toml::value v3 = "0xDEADBEEF"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_integer());
|
||||||
|
BOOST_TEST(v2.is_integer());
|
||||||
|
BOOST_TEST(v3.is_integer());
|
||||||
|
BOOST_TEST(toml::get<toml::integer>(v1) == 123456);
|
||||||
|
BOOST_TEST(toml::get<toml::integer>(v2) == 2);
|
||||||
|
BOOST_TEST(toml::get<toml::integer>(v3) == 0xDEADBEEF);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = "3.1415"_toml;
|
||||||
|
const toml::value v2 = "6.02e+23"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_floating());
|
||||||
|
BOOST_TEST(v2.is_floating());
|
||||||
|
BOOST_TEST(toml::get<double>(v1) == 3.1415, boost::test_tools::tolerance(0.00001));
|
||||||
|
BOOST_TEST(toml::get<double>(v2) == 6.02e23, boost::test_tools::tolerance(0.0001));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = R"("foo")"_toml;
|
||||||
|
const toml::value v2 = R"('foo')"_toml;
|
||||||
|
const toml::value v3 = R"("""foo""")"_toml;
|
||||||
|
const toml::value v4 = R"('''foo''')"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_string());
|
||||||
|
BOOST_TEST(v2.is_string());
|
||||||
|
BOOST_TEST(v3.is_string());
|
||||||
|
BOOST_TEST(v4.is_string());
|
||||||
|
BOOST_TEST(toml::get<std::string>(v1) == "foo");
|
||||||
|
BOOST_TEST(toml::get<std::string>(v2) == "foo");
|
||||||
|
BOOST_TEST(toml::get<std::string>(v3) == "foo");
|
||||||
|
BOOST_TEST(toml::get<std::string>(v4) == "foo");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const toml::value v1 = R"([1,2,3])"_toml;
|
||||||
|
BOOST_TEST(v1.is_array());
|
||||||
|
const bool result = (toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3});
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v2 = R"([1,])"_toml;
|
||||||
|
BOOST_TEST(v2.is_array());
|
||||||
|
const bool result = (toml::get<std::vector<int>>(v2) == std::vector<int>{1});
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v3 = R"([[1,]])"_toml;
|
||||||
|
BOOST_TEST(v3.is_array());
|
||||||
|
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v3).front()) == std::vector<int>{1});
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v4 = R"([[1],])"_toml;
|
||||||
|
BOOST_TEST(v4.is_array());
|
||||||
|
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v4).front()) == std::vector<int>{1});
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = R"({a = 42})"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_table());
|
||||||
|
const bool result = toml::get<std::map<std::string,int>>(v1) ==
|
||||||
|
std::map<std::string,int>{{"a", 42}};
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = "1979-05-27"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_local_date());
|
||||||
|
BOOST_TEST(toml::get<toml::local_date>(v1) ==
|
||||||
|
toml::local_date(1979, toml::month_t::May, 27));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = "12:00:00"_toml;
|
||||||
|
|
||||||
|
BOOST_TEST(v1.is_local_time());
|
||||||
|
const bool result = toml::get<std::chrono::hours>(v1) == std::chrono::hours(12);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = "1979-05-27T07:32:00"_toml;
|
||||||
|
BOOST_TEST(v1.is_local_datetime());
|
||||||
|
BOOST_TEST(toml::get<toml::local_datetime>(v1) ==
|
||||||
|
toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||||
|
toml::local_time(7, 32, 0)));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v1 = "1979-05-27T07:32:00Z"_toml;
|
||||||
|
BOOST_TEST(v1.is_offset_datetime());
|
||||||
|
BOOST_TEST(toml::get<toml::offset_datetime>(v1) ==
|
||||||
|
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||||
|
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_file_as_u8_literal)
|
||||||
|
{
|
||||||
|
using namespace toml::literals::toml_literals;
|
||||||
|
|
||||||
{
|
{
|
||||||
const toml::value r{{"a", 42}, {"b", "baz"}};
|
const toml::value r{{"a", 42}, {"b", "baz"}};
|
||||||
const toml::value v = u8R"(
|
const toml::value v = u8R"(
|
||||||
@@ -59,7 +223,7 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
BOOST_AUTO_TEST_CASE(test_value_as_u8_literal)
|
||||||
{
|
{
|
||||||
using namespace toml::literals::toml_literals;
|
using namespace toml::literals::toml_literals;
|
||||||
|
|
||||||
@@ -98,15 +262,18 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
|||||||
const toml::value v2 = u8R"('foo')"_toml;
|
const toml::value v2 = u8R"('foo')"_toml;
|
||||||
const toml::value v3 = u8R"("""foo""")"_toml;
|
const toml::value v3 = u8R"("""foo""")"_toml;
|
||||||
const toml::value v4 = u8R"('''foo''')"_toml;
|
const toml::value v4 = u8R"('''foo''')"_toml;
|
||||||
|
const toml::value v5 = u8R"("ひらがな")"_toml;
|
||||||
|
|
||||||
BOOST_TEST(v1.is_string());
|
BOOST_TEST(v1.is_string());
|
||||||
BOOST_TEST(v2.is_string());
|
BOOST_TEST(v2.is_string());
|
||||||
BOOST_TEST(v3.is_string());
|
BOOST_TEST(v3.is_string());
|
||||||
BOOST_TEST(v4.is_string());
|
BOOST_TEST(v4.is_string());
|
||||||
|
BOOST_TEST(v5.is_string());
|
||||||
BOOST_TEST(toml::get<std::string>(v1) == "foo");
|
BOOST_TEST(toml::get<std::string>(v1) == "foo");
|
||||||
BOOST_TEST(toml::get<std::string>(v2) == "foo");
|
BOOST_TEST(toml::get<std::string>(v2) == "foo");
|
||||||
BOOST_TEST(toml::get<std::string>(v3) == "foo");
|
BOOST_TEST(toml::get<std::string>(v3) == "foo");
|
||||||
BOOST_TEST(toml::get<std::string>(v4) == "foo");
|
BOOST_TEST(toml::get<std::string>(v4) == "foo");
|
||||||
|
BOOST_TEST(toml::get<std::string>(v5) == "\xE3\x81\xB2\xE3\x82\x89\xE3\x81\x8C\xE3\x81\xAA");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -164,7 +331,7 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
|||||||
toml::local_time(7, 32, 0)));
|
toml::local_time(7, 32, 0)));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const toml::value v1 = "1979-05-27T07:32:00Z"_toml;
|
const toml::value v1 = u8"1979-05-27T07:32:00Z"_toml;
|
||||||
BOOST_TEST(v1.is_offset_datetime());
|
BOOST_TEST(v1.is_offset_datetime());
|
||||||
BOOST_TEST(toml::get<toml::offset_datetime>(v1) ==
|
BOOST_TEST(toml::get<toml::offset_datetime>(v1) ==
|
||||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||||
|
|||||||
@@ -172,3 +172,18 @@ BOOST_AUTO_TEST_CASE(test_heterogeneous_array)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_comments_after_comma)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
array a;
|
||||||
|
a.push_back("foo");
|
||||||
|
a.push_back("bar");
|
||||||
|
a.push_back("baz");
|
||||||
|
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||||
|
"[ \"foo\" # comment\n"
|
||||||
|
", \"bar\" # comment\n"
|
||||||
|
", \"baz\" # comment\n"
|
||||||
|
"]", toml::value(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#define TOML11_TEST_PARSE_EQUAL(psr, tkn, expct) \
|
#define TOML11_TEST_PARSE_EQUAL(psr, tkn, expct) \
|
||||||
do { \
|
do { \
|
||||||
const std::string token(tkn); \
|
const std::string token(tkn); \
|
||||||
toml::detail::location<std::string> loc("test", token); \
|
toml::detail::location loc("test", token); \
|
||||||
const auto result = psr(loc); \
|
const auto result = psr(loc); \
|
||||||
BOOST_TEST(result.is_ok()); \
|
BOOST_TEST(result.is_ok()); \
|
||||||
if(result.is_ok()){ \
|
if(result.is_ok()){ \
|
||||||
@@ -23,7 +23,7 @@ do { \
|
|||||||
#define TOML11_TEST_PARSE_EQUAL_VALUE(psr, tkn, expct) \
|
#define TOML11_TEST_PARSE_EQUAL_VALUE(psr, tkn, expct) \
|
||||||
do { \
|
do { \
|
||||||
const std::string token(tkn); \
|
const std::string token(tkn); \
|
||||||
toml::detail::location<std::string> loc("test", token); \
|
toml::detail::location loc("test", token); \
|
||||||
const auto result = psr(loc); \
|
const auto result = psr(loc); \
|
||||||
BOOST_TEST(result.is_ok()); \
|
BOOST_TEST(result.is_ok()); \
|
||||||
if(result.is_ok()){ \
|
if(result.is_ok()){ \
|
||||||
|
|||||||
@@ -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");
|
||||||
@@ -779,6 +779,22 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
|
|||||||
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
|
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// without newline
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"a = 0"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
|
||||||
|
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// CRLF
|
// CRLF
|
||||||
|
|
||||||
@@ -889,3 +905,41 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_parse_function_compiles)
|
||||||
|
{
|
||||||
|
// toml::parse("");
|
||||||
|
const auto string_literal = toml::parse("toml/tests/example.toml");
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("string_literal");
|
||||||
|
|
||||||
|
const char* fname_cstring = "toml/tests/example.toml";
|
||||||
|
// toml::parse(const char*);
|
||||||
|
const auto cstring = toml::parse(fname_cstring);
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("const char*");
|
||||||
|
|
||||||
|
// toml::parse(char*);
|
||||||
|
std::array<char, 24> fname_char_ptr;
|
||||||
|
std::strncpy(fname_char_ptr.data(), fname_cstring, 24);
|
||||||
|
const auto char_ptr = toml::parse(fname_char_ptr.data());
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("char*");
|
||||||
|
|
||||||
|
// toml::parse(const std::string&);
|
||||||
|
const std::string fname_string("toml/tests/example.toml");
|
||||||
|
const auto string = toml::parse(fname_string);
|
||||||
|
std::string fname_string_mut("toml/tests/example.toml");
|
||||||
|
// toml::parse(std::string&);
|
||||||
|
const auto string_mutref = toml::parse(fname_string_mut);
|
||||||
|
// toml::parse(std::string&&);
|
||||||
|
const auto string_rref = toml::parse(std::move(fname_string_mut));
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("strings");
|
||||||
|
|
||||||
|
#ifdef TOML11_HAS_STD_FILESYSTEM
|
||||||
|
const std::filesystem::path fname_path(fname_string.begin(), fname_string.end());
|
||||||
|
const auto filesystem_path = toml::parse(fname_path);
|
||||||
|
BOOST_TEST_MESSAGE("path");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(test_inf)
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
const std::string token("inf");
|
const std::string token("inf");
|
||||||
toml::detail::location<std::string> loc("test", token);
|
toml::detail::location loc("test", token);
|
||||||
const auto r = parse_floating(loc);
|
const auto r = parse_floating(loc);
|
||||||
BOOST_CHECK(r.is_ok());
|
BOOST_CHECK(r.is_ok());
|
||||||
BOOST_CHECK(std::isinf(r.unwrap().first));
|
BOOST_CHECK(std::isinf(r.unwrap().first));
|
||||||
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(test_inf)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
const std::string token("+inf");
|
const std::string token("+inf");
|
||||||
toml::detail::location<std::string> loc("test", token);
|
toml::detail::location loc("test", token);
|
||||||
const auto r = parse_floating(loc);
|
const auto r = parse_floating(loc);
|
||||||
BOOST_CHECK(r.is_ok());
|
BOOST_CHECK(r.is_ok());
|
||||||
BOOST_CHECK(std::isinf(r.unwrap().first));
|
BOOST_CHECK(std::isinf(r.unwrap().first));
|
||||||
@@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(test_inf)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
const std::string token("-inf");
|
const std::string token("-inf");
|
||||||
toml::detail::location<std::string> loc("test", token);
|
toml::detail::location loc("test", token);
|
||||||
const auto r = parse_floating(loc);
|
const auto r = parse_floating(loc);
|
||||||
BOOST_CHECK(r.is_ok());
|
BOOST_CHECK(r.is_ok());
|
||||||
BOOST_CHECK(std::isinf(r.unwrap().first));
|
BOOST_CHECK(std::isinf(r.unwrap().first));
|
||||||
@@ -156,21 +156,21 @@ BOOST_AUTO_TEST_CASE(test_nan)
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
const std::string token("nan");
|
const std::string token("nan");
|
||||||
toml::detail::location<std::string> loc("test", token);
|
toml::detail::location loc("test", token);
|
||||||
const auto r = parse_floating(loc);
|
const auto r = parse_floating(loc);
|
||||||
BOOST_CHECK(r.is_ok());
|
BOOST_CHECK(r.is_ok());
|
||||||
BOOST_CHECK(std::isnan(r.unwrap().first));
|
BOOST_CHECK(std::isnan(r.unwrap().first));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const std::string token("+nan");
|
const std::string token("+nan");
|
||||||
toml::detail::location<std::string> loc("test", token);
|
toml::detail::location loc("test", token);
|
||||||
const auto r = parse_floating(loc);
|
const auto r = parse_floating(loc);
|
||||||
BOOST_CHECK(r.is_ok());
|
BOOST_CHECK(r.is_ok());
|
||||||
BOOST_CHECK(std::isnan(r.unwrap().first));
|
BOOST_CHECK(std::isnan(r.unwrap().first));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const std::string token("-nan");
|
const std::string token("-nan");
|
||||||
toml::detail::location<std::string> loc("test", token);
|
toml::detail::location loc("test", token);
|
||||||
const auto r = parse_floating(loc);
|
const auto r = parse_floating(loc);
|
||||||
BOOST_CHECK(r.is_ok());
|
BOOST_CHECK(r.is_ok());
|
||||||
BOOST_CHECK(std::isnan(r.unwrap().first));
|
BOOST_CHECK(std::isnan(r.unwrap().first));
|
||||||
|
|||||||
@@ -46,3 +46,19 @@ BOOST_AUTO_TEST_CASE(test_inline_table_value)
|
|||||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "{type.name = \"pug\"}", value(t));
|
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "{type.name = \"pug\"}", value(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_inline_table_immutability)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::istringstream stream(std::string(
|
||||||
|
"a = {b = 1}\n"
|
||||||
|
"a.c = 2\n"));
|
||||||
|
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::istringstream stream(std::string(
|
||||||
|
"a = {b = {c = 1}}\n"
|
||||||
|
"a.b.d = 2\n"));
|
||||||
|
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(test_normal_table)
|
|||||||
"key2 = 42\n"
|
"key2 = 42\n"
|
||||||
"key3 = 3.14\n"
|
"key3 = 3.14\n"
|
||||||
);
|
);
|
||||||
location<std::string> loc("test", table);
|
location loc("test", table);
|
||||||
|
|
||||||
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
|
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
|
||||||
BOOST_TEST(result.is_ok());
|
BOOST_TEST(result.is_ok());
|
||||||
@@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(test_nested_table)
|
|||||||
"a.b = \"value\"\n"
|
"a.b = \"value\"\n"
|
||||||
"a.c.d = 42\n"
|
"a.c.d = 42\n"
|
||||||
);
|
);
|
||||||
location<std::string> loc("test", table);
|
location loc("test", table);
|
||||||
|
|
||||||
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
|
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
|
||||||
BOOST_TEST(result.is_ok());
|
BOOST_TEST(result.is_ok());
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
|
||||||
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
|
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
|
||||||
{
|
{
|
||||||
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
|
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
|
||||||
@@ -40,35 +39,3 @@ BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
|
|||||||
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
|
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
|
||||||
expected_multi_line_array);
|
expected_multi_line_array);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
|
|
||||||
{
|
|
||||||
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
|
|
||||||
|
|
||||||
const auto the = toml::find<toml::table>(data, "the");
|
|
||||||
BOOST_TEST(toml::get<std::string>(the.at("test_string")) ==
|
|
||||||
std::string(u8"Ýôú'ℓℓ λáƭè ₥è áƒƭèř ƭλïƨ - #"));
|
|
||||||
|
|
||||||
const auto hard = toml::get<toml::table>(the.at("hard"));
|
|
||||||
const std::vector<std::string> expected_the_hard_test_array{"] ", " # "};
|
|
||||||
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array")) ==
|
|
||||||
expected_the_hard_test_array);
|
|
||||||
const std::vector<std::string> expected_the_hard_test_array2{
|
|
||||||
std::string(u8"Tèƨƭ #11 ]ƥřôƲèδ ƭλáƭ"),
|
|
||||||
std::string(u8"Éжƥèřï₥èñƭ #9 ωáƨ á ƨúççèƨƨ")};
|
|
||||||
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array2")) ==
|
|
||||||
expected_the_hard_test_array2);
|
|
||||||
BOOST_TEST(toml::get<std::string>(hard.at("another_test_string")) ==
|
|
||||||
std::string(u8"§á₥è ƭλïñϱ, βúƭ ωïƭλ á ƨƭřïñϱ #"));
|
|
||||||
BOOST_TEST(toml::get<std::string>(hard.at("harder_test_string")) ==
|
|
||||||
std::string(u8" Âñδ ωλèñ \"'ƨ ářè ïñ ƭλè ƨƭřïñϱ, áℓôñϱ ωïƭλ # \""));
|
|
||||||
|
|
||||||
const auto bit = toml::get<toml::table>(hard.at(std::string(u8"βïƭ#")));
|
|
||||||
BOOST_TEST(toml::get<std::string>(bit.at(std::string(u8"ωλáƭ?"))) ==
|
|
||||||
std::string(u8"Ýôú δôñ'ƭ ƭλïñƙ ƨô₥è úƨèř ωôñ'ƭ δô ƭλáƭ?"));
|
|
||||||
const std::vector<std::string> expected_multi_line_array{"]"};
|
|
||||||
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
|
|
||||||
expected_multi_line_array);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -966,3 +966,54 @@ BOOST_AUTO_TEST_CASE(test_value_bracket)
|
|||||||
BOOST_CHECK_THROW(v1["foo"], toml::type_error);
|
BOOST_CHECK_THROW(v1["foo"], toml::type_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_value_map_methods)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
|
||||||
|
|
||||||
|
BOOST_TEST(v1.count("foo") == 1u);
|
||||||
|
BOOST_TEST(v1.count("bar") == 1u);
|
||||||
|
BOOST_TEST(v1.count("baz") == 1u);
|
||||||
|
BOOST_TEST(v1.count("qux") == 0u);
|
||||||
|
|
||||||
|
BOOST_TEST( v1.contains("foo"));
|
||||||
|
BOOST_TEST( v1.contains("bar"));
|
||||||
|
BOOST_TEST( v1.contains("baz"));
|
||||||
|
BOOST_TEST(!v1.contains("qux"));
|
||||||
|
|
||||||
|
BOOST_TEST(v1.size() == 3);
|
||||||
|
|
||||||
|
v1["qux"] = 54;
|
||||||
|
BOOST_TEST(v1.count("qux") == 1u);
|
||||||
|
BOOST_TEST(v1.contains("qux"));
|
||||||
|
BOOST_TEST(v1.size() == 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v1(42);
|
||||||
|
BOOST_CHECK_THROW(v1.size() , toml::type_error);
|
||||||
|
BOOST_CHECK_THROW(v1.count("k") , toml::type_error);
|
||||||
|
BOOST_CHECK_THROW(v1.contains("k"), toml::type_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_value_vector_methods)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
toml::value v1{1, 2, 3, 4, 5};
|
||||||
|
|
||||||
|
BOOST_TEST(v1.size() == 5);
|
||||||
|
|
||||||
|
v1.push_back(6);
|
||||||
|
BOOST_TEST(v1.size() == 6);
|
||||||
|
|
||||||
|
v1.emplace_back(6);
|
||||||
|
BOOST_TEST(v1.size() == 7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v1(42);
|
||||||
|
BOOST_CHECK_THROW(v1.size(), toml::type_error);
|
||||||
|
BOOST_CHECK_THROW(v1.push_back(1), toml::type_error);
|
||||||
|
BOOST_CHECK_THROW(v1.emplace_back(1), toml::type_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
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 = R"(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.
|
||||||
@@ -56,13 +58,9 @@ struct character
|
|||||||
{
|
{
|
||||||
static constexpr char target = C;
|
static constexpr char target = C;
|
||||||
|
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
|
||||||
"internal error: container::value_type should be `char`.");
|
|
||||||
|
|
||||||
if(loc.iter() == loc.end()) {return none();}
|
if(loc.iter() == loc.end()) {return none();}
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
|
|
||||||
@@ -73,7 +71,7 @@ struct character
|
|||||||
}
|
}
|
||||||
loc.advance(); // update location
|
loc.advance(); // update location
|
||||||
|
|
||||||
return ok(region<Cont>(loc, first, loc.iter()));
|
return ok(region(loc, first, loc.iter()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<char C>
|
template<char C>
|
||||||
@@ -89,13 +87,9 @@ struct in_range
|
|||||||
static constexpr char upper = Up;
|
static constexpr char upper = Up;
|
||||||
static constexpr char lower = Low;
|
static constexpr char lower = Low;
|
||||||
|
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
|
||||||
"internal error: container::value_type should be `char`.");
|
|
||||||
|
|
||||||
if(loc.iter() == loc.end()) {return none();}
|
if(loc.iter() == loc.end()) {return none();}
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
|
|
||||||
@@ -106,7 +100,7 @@ struct in_range
|
|||||||
}
|
}
|
||||||
|
|
||||||
loc.advance();
|
loc.advance();
|
||||||
return ok(region<Cont>(loc, first, loc.iter()));
|
return ok(region(loc, first, loc.iter()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<char L, char U> constexpr char in_range<L, U>::upper;
|
template<char L, char U> constexpr char in_range<L, U>::upper;
|
||||||
@@ -117,13 +111,9 @@ template<char L, char U> constexpr char in_range<L, U>::lower;
|
|||||||
template<typename Combinator>
|
template<typename Combinator>
|
||||||
struct exclude
|
struct exclude
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
|
||||||
"internal error: container::value_type should be `char`.");
|
|
||||||
|
|
||||||
if(loc.iter() == loc.end()) {return none();}
|
if(loc.iter() == loc.end()) {return none();}
|
||||||
auto first = loc.iter();
|
auto first = loc.iter();
|
||||||
|
|
||||||
@@ -134,7 +124,7 @@ struct exclude
|
|||||||
return none();
|
return none();
|
||||||
}
|
}
|
||||||
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
|
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
|
||||||
return ok(region<Cont>(loc, first, loc.iter()));
|
return ok(region(loc, first, loc.iter()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,19 +132,15 @@ struct exclude
|
|||||||
template<typename Combinator>
|
template<typename Combinator>
|
||||||
struct maybe
|
struct maybe
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
|
||||||
"internal error: container::value_type should be `char`.");
|
|
||||||
|
|
||||||
const auto rslt = Combinator::invoke(loc);
|
const auto rslt = Combinator::invoke(loc);
|
||||||
if(rslt.is_ok())
|
if(rslt.is_ok())
|
||||||
{
|
{
|
||||||
return rslt;
|
return rslt;
|
||||||
}
|
}
|
||||||
return ok(region<Cont>(loc));
|
return ok(region(loc));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -164,13 +150,9 @@ struct sequence;
|
|||||||
template<typename Head, typename ... Tail>
|
template<typename Head, typename ... Tail>
|
||||||
struct sequence<Head, Tail...>
|
struct sequence<Head, Tail...>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
|
||||||
"internal error: container::value_type should be `char`.");
|
|
||||||
|
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
@@ -182,9 +164,9 @@ struct sequence<Head, Tail...>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// called from the above function only, recursively.
|
// called from the above function only, recursively.
|
||||||
template<typename Cont, typename Iterator>
|
template<typename Iterator>
|
||||||
static result<region<Cont>, none_t>
|
static result<region, none_t>
|
||||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
invoke(location& loc, region reg, Iterator first)
|
||||||
{
|
{
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
@@ -201,9 +183,9 @@ template<typename Head>
|
|||||||
struct sequence<Head>
|
struct sequence<Head>
|
||||||
{
|
{
|
||||||
// would be called from sequence<T ...>::invoke only.
|
// would be called from sequence<T ...>::invoke only.
|
||||||
template<typename Cont, typename Iterator>
|
template<typename Iterator>
|
||||||
static result<region<Cont>, none_t>
|
static result<region, none_t>
|
||||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
invoke(location& loc, region reg, Iterator first)
|
||||||
{
|
{
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
@@ -222,13 +204,9 @@ struct either;
|
|||||||
template<typename Head, typename ... Tail>
|
template<typename Head, typename ... Tail>
|
||||||
struct either<Head, Tail...>
|
struct either<Head, Tail...>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
|
||||||
"internal error: container::value_type should be `char`.");
|
|
||||||
|
|
||||||
const auto rslt = Head::invoke(loc);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_ok()) {return rslt;}
|
if(rslt.is_ok()) {return rslt;}
|
||||||
return either<Tail...>::invoke(loc);
|
return either<Tail...>::invoke(loc);
|
||||||
@@ -237,12 +215,9 @@ struct either<Head, Tail...>
|
|||||||
template<typename Head>
|
template<typename Head>
|
||||||
struct either<Head>
|
struct either<Head>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
|
||||||
"internal error: container::value_type should be `char`.");
|
|
||||||
return Head::invoke(loc);
|
return Head::invoke(loc);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -257,11 +232,10 @@ struct unlimited{};
|
|||||||
template<typename T, std::size_t N>
|
template<typename T, std::size_t N>
|
||||||
struct repeat<T, exactly<N>>
|
struct repeat<T, exactly<N>>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region retval(loc);
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
for(std::size_t i=0; i<N; ++i)
|
for(std::size_t i=0; i<N; ++i)
|
||||||
{
|
{
|
||||||
@@ -280,11 +254,10 @@ struct repeat<T, exactly<N>>
|
|||||||
template<typename T, std::size_t N>
|
template<typename T, std::size_t N>
|
||||||
struct repeat<T, at_least<N>>
|
struct repeat<T, at_least<N>>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region retval(loc);
|
||||||
|
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
for(std::size_t i=0; i<N; ++i)
|
for(std::size_t i=0; i<N; ++i)
|
||||||
@@ -312,11 +285,10 @@ struct repeat<T, at_least<N>>
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct repeat<T, unlimited>
|
struct repeat<T, unlimited>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
static result<region, none_t>
|
||||||
static result<region<Cont>, none_t>
|
invoke(location& loc)
|
||||||
invoke(location<Cont>& loc)
|
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region retval(loc);
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc);
|
auto rslt = T::invoke(loc);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -172,9 +173,9 @@ template<typename charT, typename traits>
|
|||||||
std::basic_ostream<charT, traits>&
|
std::basic_ostream<charT, traits>&
|
||||||
operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
|
operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
|
||||||
{
|
{
|
||||||
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
|
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
|
||||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month + 1) << '-';
|
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
|
||||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day );
|
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ) ;
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,18 @@
|
|||||||
// 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
|
||||||
{
|
{
|
||||||
|
|
||||||
struct exception : public std::exception
|
struct exception : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
exception(const source_location& loc): loc_(loc) {}
|
explicit exception(const source_location& loc): loc_(loc) {}
|
||||||
virtual ~exception() noexcept override = default;
|
virtual ~exception() noexcept override = default;
|
||||||
virtual const char* what() const noexcept override {return "";}
|
virtual const char* what() const noexcept override {return "";}
|
||||||
virtual source_location const& location() const noexcept {return loc_;}
|
virtual source_location const& location() const noexcept {return loc_;}
|
||||||
|
|||||||
294
toml/get.hpp
294
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
|
||||||
{
|
{
|
||||||
@@ -188,8 +189,7 @@ get(const basic_value<C, M, V>& v)
|
|||||||
{
|
{
|
||||||
throw type_error(detail::format_underline("toml::value: "
|
throw type_error(detail::format_underline("toml::value: "
|
||||||
"bad_cast to std::chrono::system_clock::time_point", {
|
"bad_cast to std::chrono::system_clock::time_point", {
|
||||||
{std::addressof(detail::get_region(v)),
|
{v.location(), concat_to_string("the actual type is ", v.type())}
|
||||||
concat_to_string("the actual type is ", v.type())}
|
|
||||||
}), v.location());
|
}), v.location());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,24 +198,24 @@ 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>
|
||||||
get(const basic_value<C, M, V>&);
|
get(const basic_value<C, M, V>&);
|
||||||
@@ -259,37 +259,69 @@ template<typename T, typename C,
|
|||||||
std::size_t S = sizeof(::toml::from<T>)>
|
std::size_t S = sizeof(::toml::from<T>)>
|
||||||
T get(const basic_value<C, M, V>&);
|
T get(const basic_value<C, M, V>&);
|
||||||
|
|
||||||
|
// T(const toml::value&) and T is not toml::basic_value
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::conjunction<
|
||||||
|
detail::negation<detail::is_basic_value<T>>,
|
||||||
|
std::is_constructible<T, const basic_value<C, M, V>&>
|
||||||
|
>::value, T>
|
||||||
|
get(const basic_value<C, M, V>&);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// array-like types; most likely STL container, like std::vector, etc.
|
// array-like types; most likely STL container, like std::vector, etc.
|
||||||
|
|
||||||
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)
|
||||||
@@ -303,7 +335,7 @@ get(const basic_value<C, M, V>& v)
|
|||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"toml::get: specified container size is ", container.size(),
|
"toml::get: specified container size is ", container.size(),
|
||||||
" but there are ", ar.size(), " elements in toml array."), {
|
" but there are ", ar.size(), " elements in toml array."), {
|
||||||
{std::addressof(detail::get_region(v)), "here"}
|
{v.location(), "here"}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
||||||
@@ -327,9 +359,7 @@ get(const basic_value<C, M, V>& v)
|
|||||||
{
|
{
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"toml::get: specified std::pair but there are ", ar.size(),
|
"toml::get: specified std::pair but there are ", ar.size(),
|
||||||
" elements in toml array."), {
|
" elements in toml array."), {{v.location(), "here"}}));
|
||||||
{std::addressof(detail::get_region(v)), "here"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return std::make_pair(::toml::get<first_type >(ar.at(0)),
|
return std::make_pair(::toml::get<first_type >(ar.at(0)),
|
||||||
::toml::get<second_type>(ar.at(1)));
|
::toml::get<second_type>(ar.at(1)));
|
||||||
@@ -359,9 +389,7 @@ get(const basic_value<C, M, V>& v)
|
|||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
"toml::get: specified std::tuple with ",
|
"toml::get: specified std::tuple with ",
|
||||||
std::tuple_size<T>::value, " elements, but there are ", ar.size(),
|
std::tuple_size<T>::value, " elements, but there are ", ar.size(),
|
||||||
" elements in toml array."), {
|
" elements in toml array."), {{v.location(), "here"}}));
|
||||||
{std::addressof(detail::get_region(v)), "here"}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return detail::get_tuple_impl<T>(ar,
|
return detail::get_tuple_impl<T>(ar,
|
||||||
detail::make_index_sequence<std::tuple_size<T>::value>{});
|
detail::make_index_sequence<std::tuple_size<T>::value>{});
|
||||||
@@ -387,7 +415,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;
|
||||||
}
|
}
|
||||||
@@ -417,6 +445,17 @@ T get(const basic_value<C, M, V>& v)
|
|||||||
return ::toml::from<T>::from_toml(v);
|
return ::toml::from<T>::from_toml(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::conjunction<
|
||||||
|
detail::negation<detail::is_basic_value<T>>,
|
||||||
|
std::is_constructible<T, const basic_value<C, M, V>&>
|
||||||
|
>::value, T>
|
||||||
|
get(const basic_value<C, M, V>& v)
|
||||||
|
{
|
||||||
|
return T(v);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// find
|
// find
|
||||||
|
|
||||||
@@ -429,10 +468,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);
|
||||||
}
|
}
|
||||||
@@ -443,10 +479,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);
|
||||||
}
|
}
|
||||||
@@ -457,14 +490,51 @@ 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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// find(value, idx)
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V> const&
|
||||||
|
find(const basic_value<C, M, V>& v, const std::size_t idx)
|
||||||
|
{
|
||||||
|
const auto& ary = v.as_array();
|
||||||
|
if(ary.size() <= idx)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
||||||
|
}
|
||||||
|
return ary.at(idx);
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V>& find(basic_value<C, M, V>& v, const std::size_t idx)
|
||||||
|
{
|
||||||
|
auto& ary = v.as_array();
|
||||||
|
if(ary.size() <= idx)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
||||||
|
}
|
||||||
|
return ary.at(idx);
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V> find(basic_value<C, M, V>&& v, const std::size_t idx)
|
||||||
|
{
|
||||||
|
auto& ary = v.as_array();
|
||||||
|
if(ary.size() <= idx)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
||||||
|
}
|
||||||
|
return basic_value<C, M, V>(std::move(ary.at(idx)));
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// find<T>(value, key);
|
// find<T>(value, key);
|
||||||
|
|
||||||
@@ -476,10 +546,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));
|
||||||
}
|
}
|
||||||
@@ -492,10 +559,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));
|
||||||
}
|
}
|
||||||
@@ -508,65 +572,151 @@ 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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// find<T>(value, idx)
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
|
||||||
|
find(const basic_value<C, M, V>& v, const std::size_t idx)
|
||||||
|
{
|
||||||
|
const auto& ary = v.as_array();
|
||||||
|
if(ary.size() <= idx)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(ary.at(idx));
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
||||||
|
find(basic_value<C, M, V>& v, const std::size_t idx)
|
||||||
|
{
|
||||||
|
auto& ary = v.as_array();
|
||||||
|
if(ary.size() <= idx)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(ary.at(idx));
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
||||||
|
find(basic_value<C, M, V>&& v, const std::size_t idx)
|
||||||
|
{
|
||||||
|
typename basic_value<C, M, V>::array_type ary = std::move(v).as_array();
|
||||||
|
if(ary.size() <= idx)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"index ", idx, " is out of range"), {{v.location(), "in this array"}}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(std::move(ary.at(idx)));
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// toml::find(toml::value, toml::key, Ts&& ... keys)
|
// toml::find(toml::value, toml::key, Ts&& ... keys)
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
// It suppresses warnings by -Wsign-conversion. Let's say we have the following
|
||||||
|
// code.
|
||||||
|
// ```cpp
|
||||||
|
// const auto x = toml::find<std::string>(data, "array", 0);
|
||||||
|
// ```
|
||||||
|
// Here, the type of literal number `0` is `int`. `int` is a signed integer.
|
||||||
|
// `toml::find` takes `std::size_t` as an index. So it causes implicit sign
|
||||||
|
// conversion and `-Wsign-conversion` warns about it. Using `0u` instead of `0`
|
||||||
|
// suppresses the warning, but it makes user code messy.
|
||||||
|
// To suppress this warning, we need to be aware of type conversion caused
|
||||||
|
// by `toml::find(v, key1, key2, ... keys)`. But the thing is that the types of
|
||||||
|
// keys can be any combination of {string-like, size_t-like}. Of course we can't
|
||||||
|
// write down all the combinations. Thus we need to use some function that
|
||||||
|
// recognize the type of argument and cast it into `std::string` or
|
||||||
|
// `std::size_t` depending on the context.
|
||||||
|
// `key_cast` does the job. It has 2 overloads. One is invoked when the
|
||||||
|
// argument type is an integer and cast the argument into `std::size_t`. The
|
||||||
|
// other is invoked when the argument type is not an integer, possibly one of
|
||||||
|
// std::string, const char[N] or const char*, and construct std::string from
|
||||||
|
// the argument.
|
||||||
|
// `toml::find(v, k1, k2, ... ks)` uses `key_cast` before passing `ks` to
|
||||||
|
// `toml::find(v, k)` to suppress -Wsign-conversion.
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
enable_if_t<conjunction<std::is_integral<remove_cvref_t<T>>,
|
||||||
|
negation<std::is_same<remove_cvref_t<T>, bool>>>::value, std::size_t>
|
||||||
|
key_cast(T&& v) noexcept
|
||||||
|
{
|
||||||
|
return std::size_t(v);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
enable_if_t<negation<conjunction<std::is_integral<remove_cvref_t<T>>,
|
||||||
|
negation<std::is_same<remove_cvref_t<T>, bool>>>>::value, std::string>
|
||||||
|
key_cast(T&& v) noexcept
|
||||||
|
{
|
||||||
|
return std::string(std::forward<T>(v));
|
||||||
|
}
|
||||||
|
} // detail
|
||||||
|
|
||||||
template<typename C,
|
template<typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
typename ... Ts>
|
typename Key1, typename Key2, typename ... Keys>
|
||||||
const basic_value<C, M, V>&
|
const basic_value<C, M, V>&
|
||||||
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||||
{
|
{
|
||||||
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
return ::toml::find(::toml::find(v, detail::key_cast(k1)),
|
||||||
|
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
template<typename C,
|
template<typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
typename ... Ts>
|
typename Key1, typename Key2, typename ... Keys>
|
||||||
basic_value<C, M, V>&
|
basic_value<C, M, V>&
|
||||||
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||||
{
|
{
|
||||||
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
return ::toml::find(::toml::find(v, detail::key_cast(k1)),
|
||||||
|
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
template<typename C,
|
template<typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
typename ... Ts>
|
typename Key1, typename Key2, typename ... Keys>
|
||||||
basic_value<C, M, V>
|
basic_value<C, M, V>
|
||||||
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
|
find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||||
{
|
{
|
||||||
return ::toml::find(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
|
return ::toml::find(::toml::find(std::move(v), std::forward<Key1>(k1)),
|
||||||
|
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
typename ... Ts>
|
typename Key1, typename Key2, typename ... Keys>
|
||||||
decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>()))
|
decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>()))
|
||||||
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||||
{
|
{
|
||||||
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
|
||||||
|
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
typename ... Ts>
|
typename Key1, typename Key2, typename ... Keys>
|
||||||
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
||||||
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||||
{
|
{
|
||||||
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
|
||||||
|
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
template<typename T, typename C,
|
template<typename T, typename C,
|
||||||
template<typename ...> class M, template<typename ...> class V,
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
typename ... Ts>
|
typename Key1, typename Key2, typename ... Keys>
|
||||||
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
||||||
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
|
find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||||
{
|
{
|
||||||
return ::toml::find<T>(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
|
return ::toml::find<T>(::toml::find(std::move(v), detail::key_cast(k1)),
|
||||||
|
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -11,12 +11,9 @@ inline namespace literals
|
|||||||
inline namespace toml_literals
|
inline namespace toml_literals
|
||||||
{
|
{
|
||||||
|
|
||||||
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
// implementation
|
||||||
|
inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
||||||
{
|
{
|
||||||
::toml::detail::location<std::vector<char>>
|
|
||||||
loc(/* filename = */ std::string("TOML literal encoded in a C++ code"),
|
|
||||||
/* contents = */ std::vector<char>(str, str + len));
|
|
||||||
|
|
||||||
// if there are some comments or empty lines, skip them.
|
// if there are some comments or empty lines, skip them.
|
||||||
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
|
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
|
||||||
::toml::detail::maybe<::toml::detail::lex_ws>,
|
::toml::detail::maybe<::toml::detail::lex_ws>,
|
||||||
@@ -76,11 +73,34 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
|||||||
}
|
}
|
||||||
else // none of them.
|
else // none of them.
|
||||||
{
|
{
|
||||||
throw ::toml::syntax_error(data.unwrap_err(),
|
throw ::toml::syntax_error(data.unwrap_err(), source_location(loc));
|
||||||
source_location(std::addressof(loc)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||||
|
{
|
||||||
|
::toml::detail::location loc(
|
||||||
|
std::string("TOML literal encoded in a C++ code"),
|
||||||
|
std::vector<char>(str, str + len));
|
||||||
|
return literal_internal_impl(std::move(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// value of __cplusplus in C++2a/20 mode is not fixed yet along compilers.
|
||||||
|
// So here we use the feature test macro for `char8_t` itself.
|
||||||
|
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||||
|
// value of u8"" literal has been changed from char to char8_t and char8_t is
|
||||||
|
// NOT compatible to char
|
||||||
|
inline ::toml::value operator"" _toml(const char8_t* str, std::size_t len)
|
||||||
|
{
|
||||||
|
::toml::detail::location loc(
|
||||||
|
std::string("TOML literal encoded in a C++ code"),
|
||||||
|
std::vector<char>(reinterpret_cast<const char*>(str),
|
||||||
|
reinterpret_cast<const char*>(str) + len));
|
||||||
|
return literal_internal_impl(std::move(loc));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // toml_literals
|
} // toml_literals
|
||||||
} // literals
|
} // literals
|
||||||
} // toml
|
} // toml
|
||||||
|
|||||||
708
toml/parser.hpp
708
toml/parser.hpp
File diff suppressed because it is too large
Load Diff
144
toml/region.hpp
144
toml/region.hpp
@@ -41,6 +41,7 @@ struct region_base
|
|||||||
region_base& operator=(region_base&& ) = default;
|
region_base& operator=(region_base&& ) = default;
|
||||||
|
|
||||||
virtual bool is_ok() const noexcept {return false;}
|
virtual bool is_ok() const noexcept {return false;}
|
||||||
|
virtual char front() const noexcept {return '\0';}
|
||||||
|
|
||||||
virtual std::string str() const {return std::string("unknown region");}
|
virtual std::string str() const {return std::string("unknown region");}
|
||||||
virtual std::string name() const {return std::string("unknown file");}
|
virtual std::string name() const {return std::string("unknown file");}
|
||||||
@@ -54,7 +55,7 @@ struct region_base
|
|||||||
// number of characters in the line after the region
|
// number of characters in the line after the region
|
||||||
virtual std::size_t after() const noexcept {return 0;}
|
virtual std::size_t after() const noexcept {return 0;}
|
||||||
|
|
||||||
virtual std::vector<std::string> comments()const {return {};}
|
virtual std::vector<std::string> comments() const {return {};}
|
||||||
// ```toml
|
// ```toml
|
||||||
// # comment_before
|
// # comment_before
|
||||||
// key = "value" # comment_inline
|
// key = "value" # comment_inline
|
||||||
@@ -66,22 +67,21 @@ struct region_base
|
|||||||
//
|
//
|
||||||
// it contains pointer to the file content and iterator that points the current
|
// it contains pointer to the file content and iterator that points the current
|
||||||
// location.
|
// location.
|
||||||
template<typename Container>
|
|
||||||
struct location final : public region_base
|
struct location final : public region_base
|
||||||
{
|
{
|
||||||
using const_iterator = typename Container::const_iterator;
|
using const_iterator = typename std::vector<char>::const_iterator;
|
||||||
using difference_type = typename const_iterator::difference_type;
|
using difference_type = typename const_iterator::difference_type;
|
||||||
using source_ptr = std::shared_ptr<const Container>;
|
using source_ptr = std::shared_ptr<const std::vector<char>>;
|
||||||
|
|
||||||
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
location(std::string name, std::vector<char> cont)
|
||||||
static_assert(std::is_same<std::random_access_iterator_tag,
|
: source_(std::make_shared<std::vector<char>>(std::move(cont))),
|
||||||
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin())
|
||||||
"container should be randomly accessible");
|
|
||||||
|
|
||||||
location(std::string name, Container cont)
|
|
||||||
: source_(std::make_shared<Container>(std::move(cont))), line_number_(1),
|
|
||||||
source_name_(std::move(name)), iter_(source_->cbegin())
|
|
||||||
{}
|
{}
|
||||||
|
location(std::string name, const std::string& cont)
|
||||||
|
: source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
|
||||||
|
line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin())
|
||||||
|
{}
|
||||||
|
|
||||||
location(const location&) = default;
|
location(const location&) = default;
|
||||||
location(location&&) = default;
|
location(location&&) = default;
|
||||||
location& operator=(const location&) = default;
|
location& operator=(const location&) = default;
|
||||||
@@ -89,6 +89,7 @@ struct location final : public region_base
|
|||||||
~location() = default;
|
~location() = default;
|
||||||
|
|
||||||
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
|
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
|
||||||
|
char front() const noexcept override {return *iter_;}
|
||||||
|
|
||||||
// this const prohibits codes like `++(loc.iter())`.
|
// this const prohibits codes like `++(loc.iter())`.
|
||||||
const const_iterator iter() const noexcept {return iter_;}
|
const const_iterator iter() const noexcept {return iter_;}
|
||||||
@@ -193,33 +194,27 @@ struct location final : public region_base
|
|||||||
//
|
//
|
||||||
// it contains pointer to the file content and iterator that points the first
|
// it contains pointer to the file content and iterator that points the first
|
||||||
// and last location.
|
// and last location.
|
||||||
template<typename Container>
|
|
||||||
struct region final : public region_base
|
struct region final : public region_base
|
||||||
{
|
{
|
||||||
using const_iterator = typename Container::const_iterator;
|
using const_iterator = typename std::vector<char>::const_iterator;
|
||||||
using source_ptr = std::shared_ptr<const Container>;
|
using source_ptr = std::shared_ptr<const std::vector<char>>;
|
||||||
|
|
||||||
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
|
||||||
static_assert(std::is_same<std::random_access_iterator_tag,
|
|
||||||
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
|
||||||
"container should be randomly accessible");
|
|
||||||
|
|
||||||
// delete default constructor. source_ never be null.
|
// delete default constructor. source_ never be null.
|
||||||
region() = delete;
|
region() = delete;
|
||||||
|
|
||||||
region(const location<Container>& loc)
|
explicit region(const location& loc)
|
||||||
: source_(loc.source()), source_name_(loc.name()),
|
: source_(loc.source()), source_name_(loc.name()),
|
||||||
first_(loc.iter()), last_(loc.iter())
|
first_(loc.iter()), last_(loc.iter())
|
||||||
{}
|
{}
|
||||||
region(location<Container>&& loc)
|
explicit region(location&& loc)
|
||||||
: source_(loc.source()), source_name_(loc.name()),
|
: source_(loc.source()), source_name_(loc.name()),
|
||||||
first_(loc.iter()), last_(loc.iter())
|
first_(loc.iter()), last_(loc.iter())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
region(const location<Container>& loc, const_iterator f, const_iterator l)
|
region(const location& loc, const_iterator f, const_iterator l)
|
||||||
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
|
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
|
||||||
{}
|
{}
|
||||||
region(location<Container>&& loc, const_iterator f, const_iterator l)
|
region(location&& loc, const_iterator f, const_iterator l)
|
||||||
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
|
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -240,6 +235,7 @@ struct region final : public region_base
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
|
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
|
||||||
|
char front() const noexcept override {return *first_;}
|
||||||
|
|
||||||
std::string str() const override {return make_string(first_, last_);}
|
std::string str() const override {return make_string(first_, last_);}
|
||||||
std::string line() const override
|
std::string line() const override
|
||||||
@@ -416,106 +412,6 @@ struct region final : public region_base
|
|||||||
const_iterator first_, last_;
|
const_iterator first_, last_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// to show a better error message.
|
|
||||||
inline std::string format_underline(const std::string& message,
|
|
||||||
const std::vector<std::pair<region_base const*, std::string>>& reg_com,
|
|
||||||
const std::vector<std::string>& helps = {},
|
|
||||||
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
|
||||||
{
|
|
||||||
assert(!reg_com.empty());
|
|
||||||
|
|
||||||
const auto line_num_width = static_cast<int>(std::max_element(
|
|
||||||
reg_com.begin(), reg_com.end(),
|
|
||||||
[](std::pair<region_base const*, std::string> const& lhs,
|
|
||||||
std::pair<region_base const*, std::string> const& rhs)
|
|
||||||
{
|
|
||||||
return lhs.first->line_num().size() < rhs.first->line_num().size();
|
|
||||||
}
|
|
||||||
)->first->line_num().size());
|
|
||||||
|
|
||||||
std::ostringstream retval;
|
|
||||||
|
|
||||||
if(colorize)
|
|
||||||
{
|
|
||||||
retval << color::colorize; // turn on ANSI color
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX
|
|
||||||
// Here, before `colorize` support, it does not output `[error]` prefix
|
|
||||||
// automatically. So some user may output it manually and this change may
|
|
||||||
// duplicate the prefix. To avoid it, check the first 7 characters and
|
|
||||||
// if it is "[error]", it removes that part from the message shown.
|
|
||||||
if(message.size() > 7 && message.substr(0, 7) == "[error]")
|
|
||||||
{
|
|
||||||
retval << color::bold << color::red << "[error]" << color::reset
|
|
||||||
<< color::bold << message.substr(7) << color::reset << '\n';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
retval << color::bold << color::red << "[error] " << color::reset
|
|
||||||
<< color::bold << message << color::reset << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter)
|
|
||||||
{
|
|
||||||
// if the filenames are the same, print "..."
|
|
||||||
if(iter != reg_com.begin() &&
|
|
||||||
std::prev(iter)->first->name() == iter->first->name())
|
|
||||||
{
|
|
||||||
retval << color::bold << color::blue << "\n ...\n" << color::reset;
|
|
||||||
}
|
|
||||||
else // if filename differs, print " --> filename.toml"
|
|
||||||
{
|
|
||||||
if(iter != reg_com.begin()) {retval << '\n';}
|
|
||||||
retval << color::bold << color::blue << " --> " << color::reset
|
|
||||||
<< iter->first->name() << '\n';
|
|
||||||
// add one almost-empty line for readability
|
|
||||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ')
|
|
||||||
<< color::bold << color::blue << " | " << color::reset << '\n';
|
|
||||||
}
|
|
||||||
const region_base* const reg = iter->first;
|
|
||||||
const std::string& comment = iter->second;
|
|
||||||
|
|
||||||
retval << ' ' << std::setw(line_num_width) << color::bold << color::blue
|
|
||||||
<< reg->line_num() << " | " << color::reset << reg->line() << '\n';
|
|
||||||
|
|
||||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ')
|
|
||||||
<< color::bold << color::blue << " | " << color::reset
|
|
||||||
<< make_string(reg->before(), ' ');
|
|
||||||
|
|
||||||
if(reg->size() == 1)
|
|
||||||
{
|
|
||||||
// invalid
|
|
||||||
// ^------
|
|
||||||
retval << color::bold << color::red
|
|
||||||
<< '^' << make_string(reg->after(), '-') << color::reset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// invalid
|
|
||||||
// ~~~~~~~
|
|
||||||
const auto underline_len = std::min(reg->size(), reg->line().size());
|
|
||||||
retval << color::bold << color::red
|
|
||||||
<< make_string(underline_len, '~') << color::reset;
|
|
||||||
}
|
|
||||||
retval << ' ';
|
|
||||||
retval << comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!helps.empty())
|
|
||||||
{
|
|
||||||
retval << '\n';
|
|
||||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
|
||||||
retval << color::bold << color::blue << " | " << color::reset;
|
|
||||||
for(const auto help : helps)
|
|
||||||
{
|
|
||||||
retval << color::bold << "\nHint: " << color::reset;
|
|
||||||
retval << help;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
} // toml
|
} // toml
|
||||||
#endif// TOML11_REGION_H
|
#endif// TOML11_REGION_H
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
detail::location<toml::key> loc(key, key);
|
// check the key can be a bare (unquoted) key
|
||||||
|
detail::location loc(key, std::vector<char>(key.begin(), key.end()));
|
||||||
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
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -38,12 +39,12 @@ struct source_location
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
source_location()
|
source_location()
|
||||||
: line_num_(0), column_num_(0), region_size_(0),
|
: line_num_(1), column_num_(1), region_size_(1),
|
||||||
file_name_("unknown file"), line_str_("")
|
file_name_("unknown file"), line_str_("")
|
||||||
{}
|
{}
|
||||||
|
|
||||||
explicit source_location(const detail::region_base* reg)
|
explicit source_location(const detail::region_base* reg)
|
||||||
: line_num_(0), column_num_(0), region_size_(0),
|
: line_num_(1), column_num_(1), region_size_(1),
|
||||||
file_name_("unknown file"), line_str_("")
|
file_name_("unknown file"), line_str_("")
|
||||||
{
|
{
|
||||||
if(reg)
|
if(reg)
|
||||||
@@ -60,6 +61,21 @@ struct source_location
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit source_location(const detail::region& reg)
|
||||||
|
: line_num_(static_cast<std::uint_least32_t>(std::stoul(reg.line_num()))),
|
||||||
|
column_num_(static_cast<std::uint_least32_t>(reg.before() + 1)),
|
||||||
|
region_size_(static_cast<std::uint_least32_t>(reg.size())),
|
||||||
|
file_name_(reg.name()),
|
||||||
|
line_str_ (reg.line())
|
||||||
|
{}
|
||||||
|
explicit source_location(const detail::location& loc)
|
||||||
|
: line_num_(static_cast<std::uint_least32_t>(std::stoul(loc.line_num()))),
|
||||||
|
column_num_(static_cast<std::uint_least32_t>(loc.before() + 1)),
|
||||||
|
region_size_(static_cast<std::uint_least32_t>(loc.size())),
|
||||||
|
file_name_(loc.name()),
|
||||||
|
line_str_ (loc.line())
|
||||||
|
{}
|
||||||
|
|
||||||
~source_location() = default;
|
~source_location() = default;
|
||||||
source_location(source_location const&) = default;
|
source_location(source_location const&) = default;
|
||||||
source_location(source_location &&) = default;
|
source_location(source_location &&) = default;
|
||||||
@@ -82,5 +98,135 @@ struct source_location
|
|||||||
std::string line_str_;
|
std::string line_str_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// internal error message generation.
|
||||||
|
inline std::string format_underline(const std::string& message,
|
||||||
|
const std::vector<std::pair<source_location, std::string>>& loc_com,
|
||||||
|
const std::vector<std::string>& helps = {},
|
||||||
|
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||||
|
{
|
||||||
|
std::size_t line_num_width = 0;
|
||||||
|
for(const auto& lc : loc_com)
|
||||||
|
{
|
||||||
|
std::uint_least32_t line = lc.first.line();
|
||||||
|
std::size_t digit = 0;
|
||||||
|
while(line != 0)
|
||||||
|
{
|
||||||
|
line /= 10;
|
||||||
|
digit += 1;
|
||||||
|
}
|
||||||
|
line_num_width = (std::max)(line_num_width, digit);
|
||||||
|
}
|
||||||
|
// 1 is the minimum width
|
||||||
|
line_num_width = std::max<std::size_t>(line_num_width, 1);
|
||||||
|
|
||||||
|
std::ostringstream retval;
|
||||||
|
|
||||||
|
if(colorize)
|
||||||
|
{
|
||||||
|
retval << color::colorize; // turn on ANSI color
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
// Here, before `colorize` support, it does not output `[error]` prefix
|
||||||
|
// automatically. So some user may output it manually and this change may
|
||||||
|
// duplicate the prefix. To avoid it, check the first 7 characters and
|
||||||
|
// if it is "[error]", it removes that part from the message shown.
|
||||||
|
if(message.size() > 7 && message.substr(0, 7) == "[error]")
|
||||||
|
{
|
||||||
|
retval << color::bold << color::red << "[error]" << color::reset
|
||||||
|
<< color::bold << message.substr(7) << color::reset << '\n';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval << color::bold << color::red << "[error] " << color::reset
|
||||||
|
<< color::bold << message << color::reset << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto format_one_location = [line_num_width]
|
||||||
|
(std::ostringstream& oss,
|
||||||
|
const source_location& loc, const std::string& comment) -> void
|
||||||
|
{
|
||||||
|
oss << ' ' << color::bold << color::blue
|
||||||
|
<< std::setw(static_cast<int>(line_num_width))
|
||||||
|
<< std::right << loc.line() << " | " << color::reset
|
||||||
|
<< loc.line_str() << '\n';
|
||||||
|
|
||||||
|
oss << make_string(line_num_width + 1, ' ')
|
||||||
|
<< color::bold << color::blue << " | " << color::reset
|
||||||
|
<< make_string(loc.column()-1 /*1-origin*/, ' ');
|
||||||
|
|
||||||
|
if(loc.region() == 1)
|
||||||
|
{
|
||||||
|
// invalid
|
||||||
|
// ^------
|
||||||
|
oss << color::bold << color::red << "^---" << color::reset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// invalid
|
||||||
|
// ~~~~~~~
|
||||||
|
const auto underline_len = (std::min)(
|
||||||
|
static_cast<std::size_t>(loc.region()), loc.line_str().size());
|
||||||
|
oss << color::bold << color::red
|
||||||
|
<< make_string(underline_len, '~') << color::reset;
|
||||||
|
}
|
||||||
|
oss << ' ';
|
||||||
|
oss << comment;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(!loc_com.empty());
|
||||||
|
|
||||||
|
// --> example.toml
|
||||||
|
// |
|
||||||
|
retval << color::bold << color::blue << " --> " << color::reset
|
||||||
|
<< loc_com.front().first.file_name() << '\n';
|
||||||
|
retval << make_string(line_num_width + 1, ' ')
|
||||||
|
<< color::bold << color::blue << " |\n" << color::reset;
|
||||||
|
// 1 | key value
|
||||||
|
// | ^--- missing =
|
||||||
|
format_one_location(retval, loc_com.front().first, loc_com.front().second);
|
||||||
|
|
||||||
|
// process the rest of the locations
|
||||||
|
for(std::size_t i=1; i<loc_com.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto& prev = loc_com.at(i-1);
|
||||||
|
const auto& curr = loc_com.at(i);
|
||||||
|
|
||||||
|
retval << '\n';
|
||||||
|
// if the filenames are the same, print "..."
|
||||||
|
if(prev.first.file_name() == curr.first.file_name())
|
||||||
|
{
|
||||||
|
retval << color::bold << color::blue << " ...\n" << color::reset;
|
||||||
|
}
|
||||||
|
else // if filename differs, print " --> filename.toml" again
|
||||||
|
{
|
||||||
|
retval << color::bold << color::blue << " --> " << color::reset
|
||||||
|
<< curr.first.file_name() << '\n';
|
||||||
|
retval << make_string(line_num_width + 1, ' ')
|
||||||
|
<< color::bold << color::blue << " |\n" << color::reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_one_location(retval, curr.first, curr.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!helps.empty())
|
||||||
|
{
|
||||||
|
retval << '\n';
|
||||||
|
retval << make_string(line_num_width + 1, ' ');
|
||||||
|
retval << color::bold << color::blue << " |" << color::reset;
|
||||||
|
for(const auto& help : helps)
|
||||||
|
{
|
||||||
|
retval << color::bold << "\nHint: " << color::reset;
|
||||||
|
retval << help;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
} // toml
|
} // toml
|
||||||
#endif// TOML11_SOURCE_LOCATION_HPP
|
#endif// TOML11_SOURCE_LOCATION_HPP
|
||||||
|
|||||||
@@ -16,10 +16,9 @@ struct storage
|
|||||||
{
|
{
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
|
explicit storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
|
||||||
storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
|
explicit storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
|
||||||
~storage() = default;
|
~storage() = default;
|
||||||
|
|
||||||
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
|
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
|
||||||
storage& operator=(const storage& rhs)
|
storage& operator=(const storage& rhs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)){};
|
||||||
|
|
||||||
@@ -111,6 +121,14 @@ struct has_into_toml_method
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// C++17 and/or/not
|
// C++17 and/or/not
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
|
||||||
|
using std::conjunction;
|
||||||
|
using std::disjunction;
|
||||||
|
using std::negation;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
template<typename ...> struct conjunction : std::true_type{};
|
template<typename ...> struct conjunction : std::true_type{};
|
||||||
template<typename T> struct conjunction<T> : T{};
|
template<typename T> struct conjunction<T> : T{};
|
||||||
template<typename T, typename ... Ts>
|
template<typename T, typename ... Ts>
|
||||||
@@ -128,6 +146,8 @@ struct disjunction<T, Ts...> :
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
|
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// type checkers
|
// type checkers
|
||||||
|
|
||||||
@@ -139,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{};
|
||||||
@@ -182,6 +206,13 @@ struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// C++14 index_sequence
|
// C++14 index_sequence
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L
|
||||||
|
|
||||||
|
using std::index_sequence;
|
||||||
|
using std::make_index_sequence;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
template<std::size_t ... Ns> struct index_sequence{};
|
template<std::size_t ... Ns> struct index_sequence{};
|
||||||
|
|
||||||
template<typename IS, std::size_t N> struct push_back_index_sequence{};
|
template<typename IS, std::size_t N> struct push_back_index_sequence{};
|
||||||
@@ -205,11 +236,22 @@ struct index_sequence_maker<0>
|
|||||||
template<std::size_t N>
|
template<std::size_t N>
|
||||||
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
||||||
|
|
||||||
|
#endif // __cplusplus >= 2014
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// C++14 enable_if_t
|
// C++14 enable_if_t
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L
|
||||||
|
|
||||||
|
using std::enable_if_t;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
template<bool B, typename T>
|
template<bool B, typename T>
|
||||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||||
|
|
||||||
|
#endif // __cplusplus >= 2014
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// return_type_of_t
|
// return_type_of_t
|
||||||
|
|
||||||
|
|||||||
@@ -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)]]
|
||||||
@@ -20,38 +21,41 @@
|
|||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L
|
||||||
|
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
template<typename T, typename ... Ts>
|
template<typename T, typename ... Ts>
|
||||||
inline std::unique_ptr<T> make_unique(Ts&& ... args)
|
inline std::unique_ptr<T> make_unique(Ts&& ... args)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
|
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus >= 2014
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
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
|
||||||
@@ -76,10 +80,10 @@ std::string concat_to_string(Ts&& ... args)
|
|||||||
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
|
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T>
|
||||||
T from_string(const std::string& str, U&& opt)
|
T from_string(const std::string& str, T opt)
|
||||||
{
|
{
|
||||||
T v(static_cast<T>(std::forward<U>(opt)));
|
T v(opt);
|
||||||
std::istringstream iss(str);
|
std::istringstream iss(str);
|
||||||
iss >> v;
|
iss >> v;
|
||||||
return v;
|
return v;
|
||||||
|
|||||||
825
toml/value.hpp
825
toml/value.hpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user