mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
458 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b389bbc4eb | ||
|
|
5e4eb52f84 | ||
|
|
cbd596144d | ||
|
|
85faca9cbe | ||
|
|
3509be6629 | ||
|
|
fb7b02f254 | ||
|
|
2466959cf9 | ||
|
|
a76c5b385f | ||
|
|
52621a4fd8 | ||
|
|
64cd90637b | ||
|
|
d4a6fc7953 | ||
|
|
d4eb5f3c9d | ||
|
|
cc2e453b5b | ||
|
|
8ed1a1d7e4 | ||
|
|
04209b1540 | ||
|
|
1bb5284eb5 | ||
|
|
7bd09245fa | ||
|
|
1dd15ffa26 | ||
|
|
1c2c710ec9 | ||
|
|
db72451bcf | ||
|
|
8e214ec411 | ||
|
|
655d76b828 | ||
|
|
0db935b602 | ||
|
|
ed577df40a | ||
|
|
01a0e93e5f | ||
|
|
510419fb6a | ||
|
|
7d09cdf067 | ||
|
|
828afc3b1e | ||
|
|
c32a20e1ee | ||
|
|
937a7c45fe | ||
|
|
947c995189 | ||
|
|
9b7b8908e8 | ||
|
|
22d22198ec | ||
|
|
1beb391a43 | ||
|
|
dfc625f38d | ||
|
|
22d96ed921 | ||
|
|
d2937ff4e1 | ||
|
|
087408a8fb | ||
|
|
2339b32258 | ||
|
|
5cc79bbd7b | ||
|
|
9323a315eb | ||
|
|
85d880d84e | ||
|
|
c44459dc47 | ||
|
|
1340692442 | ||
|
|
da3d5153d1 | ||
|
|
af13c2867a | ||
|
|
327f6e7701 | ||
|
|
e36eabf216 | ||
|
|
40eb1d2213 | ||
|
|
2da3b67d02 | ||
|
|
0dcf07b774 | ||
|
|
d47fe788bc | ||
|
|
78ae165096 | ||
|
|
86eefc7255 | ||
|
|
51e5d845b0 | ||
|
|
ce941c318b | ||
|
|
fd969a679b | ||
|
|
51587338cd | ||
|
|
418bfe9117 | ||
|
|
15346114ef | ||
|
|
565f43c484 | ||
|
|
f9b224c222 | ||
|
|
72789dca42 | ||
|
|
75daa2dde0 | ||
|
|
ff48387677 | ||
|
|
132aa17f97 | ||
|
|
a2f884b11e | ||
|
|
e3639d2bbc | ||
|
|
626b0e6b95 | ||
|
|
0acd2b9c88 | ||
|
|
22db720ad5 | ||
|
|
7ec3086f19 | ||
|
|
4c4e82866e | ||
|
|
41908b2cef | ||
|
|
3f197c3cab | ||
|
|
e064a5c371 | ||
|
|
e86d7c3cd3 | ||
|
|
10fd14f8b9 | ||
|
|
81c5ba9082 | ||
|
|
d7c04ed5ee | ||
|
|
b10348c576 | ||
|
|
ac949437f8 | ||
|
|
fe471bcbe9 | ||
|
|
5312b8eb0e | ||
|
|
cf8a977be2 | ||
|
|
8bb2c63a01 | ||
|
|
79c125b54f | ||
|
|
b02aaed4fc | ||
|
|
c2af975609 | ||
|
|
c3a3423fb2 | ||
|
|
6c2c804eff | ||
|
|
021d84623c | ||
|
|
bf9c9d620d | ||
|
|
bbdbae91eb | ||
|
|
72af7b48d3 | ||
|
|
c7627ff6a1 | ||
|
|
1c3c84e90a | ||
|
|
1400dd223f | ||
|
|
594accf9a7 | ||
|
|
c1378cd3d1 | ||
|
|
728f73ea24 | ||
|
|
4212985443 | ||
|
|
8e95891af1 | ||
|
|
2a987ac9ea | ||
|
|
9e1bfcc962 | ||
|
|
4a0df22548 | ||
|
|
1ba3be38d0 | ||
|
|
5be587bb68 | ||
|
|
d6efdf7d9e | ||
|
|
12d0dbc6f4 | ||
|
|
6d9e533cf1 | ||
|
|
aff6f0f574 | ||
|
|
25be97dc39 | ||
|
|
846abd9a49 | ||
|
|
9086b1114f | ||
|
|
e8f922a1b8 | ||
|
|
fdb228598d | ||
|
|
c26aa013cd | ||
|
|
5924325652 | ||
|
|
1836ddc129 | ||
|
|
1c82c7a1dc | ||
|
|
dde351ea40 | ||
|
|
dcfe39a783 | ||
|
|
2f07030d43 | ||
|
|
97cc0ef62b | ||
|
|
0e80cabe65 | ||
|
|
cd97dfcec1 | ||
|
|
e60442c6db | ||
|
|
d39fd88a17 | ||
|
|
7fb8b84143 | ||
|
|
03259e2003 | ||
|
|
bf2384d8da | ||
|
|
8ebf9c984b | ||
|
|
7354e91924 | ||
|
|
4522070391 | ||
|
|
02fd8a577b | ||
|
|
40777070ad | ||
|
|
cc1cc27613 | ||
|
|
75e297eb47 | ||
|
|
0d0605e290 | ||
|
|
23f6c931e5 | ||
|
|
518e6d4ae2 | ||
|
|
db2aa55d20 | ||
|
|
1b5107e5e3 | ||
|
|
2152c85cd1 | ||
|
|
2e4c7fb95e | ||
|
|
2ddcfb4b61 | ||
|
|
3f233d57be | ||
|
|
21732fce45 | ||
|
|
1dc09d0332 | ||
|
|
9c1708c988 | ||
|
|
84f61f7dc8 | ||
|
|
eef7106fbe | ||
|
|
a919190490 | ||
|
|
7f98740c9c | ||
|
|
e08c579e36 | ||
|
|
6dd44dc672 | ||
|
|
99e483c447 | ||
|
|
26a066ad07 | ||
|
|
acad8b1a61 | ||
|
|
605cd8ef4a | ||
|
|
bcee9f25a2 | ||
|
|
f2f2b44d87 | ||
|
|
e40dfc28eb | ||
|
|
24284c70ee | ||
|
|
dced71224d | ||
|
|
177c09f43d | ||
|
|
e434c96b7f | ||
|
|
fda0a2b9ab | ||
|
|
3eee515ce1 | ||
|
|
ca9e36a484 | ||
|
|
0858fbfced | ||
|
|
fe240e1ffc | ||
|
|
d9959fcdeb | ||
|
|
1d0b003312 | ||
|
|
0aa3773860 | ||
|
|
9745c0005f | ||
|
|
4adf36d9fd | ||
|
|
c72b27bb4b | ||
|
|
be5ffaf662 | ||
|
|
47a2a3332b | ||
|
|
9d28afa012 | ||
|
|
f09bd5b035 | ||
|
|
0dc51f95d9 | ||
|
|
cf9e86a84f | ||
|
|
5190e5148b | ||
|
|
45bd566f7a | ||
|
|
2c72329530 | ||
|
|
1b7ca8566b | ||
|
|
647381020e | ||
|
|
f04cf596eb | ||
|
|
c281539b26 | ||
|
|
58542d36be | ||
|
|
c38079f7c0 | ||
|
|
0c4594f59a | ||
|
|
e73c98490b | ||
|
|
7b9a1abdb3 | ||
|
|
891f68eab0 | ||
|
|
4b1df61142 | ||
|
|
392a260db8 | ||
|
|
7339ce39d5 | ||
|
|
287be5a575 | ||
|
|
798856946f | ||
|
|
07c1d10212 | ||
|
|
0ac3919e08 | ||
|
|
e622595426 | ||
|
|
72ee8caf09 | ||
|
|
b6e2c6e235 | ||
|
|
c5a22b9d88 | ||
|
|
7e90282175 | ||
|
|
b8291af42b | ||
|
|
cd60045014 | ||
|
|
db0d9a024b | ||
|
|
4acc563b28 | ||
|
|
dce50142e6 | ||
|
|
06e8b853ba | ||
|
|
e3092335aa | ||
|
|
31b9b79312 | ||
|
|
beb665ba58 | ||
|
|
b51ef5e869 | ||
|
|
21ea4a348d | ||
|
|
c4a803df50 | ||
|
|
c40e0dbd37 | ||
|
|
d90c26f9ac | ||
|
|
b592ddcca2 | ||
|
|
5518b2b155 | ||
|
|
ba3d41d913 | ||
|
|
8bc09d552a | ||
|
|
03c846dc9d | ||
|
|
e658a0126c | ||
|
|
6e3967e26e | ||
|
|
db1f42b5da | ||
|
|
c7d6d793cb | ||
|
|
14c6430dda | ||
|
|
b4bc704e6e | ||
|
|
3f6e873aba | ||
|
|
a3b8dd6787 | ||
|
|
c121492071 | ||
|
|
5e3f8f9105 | ||
|
|
17a15d3c18 | ||
|
|
42cc111b05 | ||
|
|
5e0ee32854 | ||
|
|
2c5cc431fe | ||
|
|
970f7cb36a | ||
|
|
b924e70e3c | ||
|
|
7782258e68 | ||
|
|
08859c36d0 | ||
|
|
d3de136562 | ||
|
|
43183e2ad1 | ||
|
|
e9144b41fb | ||
|
|
2fb8793f1a | ||
|
|
6c8a53915a | ||
|
|
db2d33ca4b | ||
|
|
935da51769 | ||
|
|
be0d4bd0a9 | ||
|
|
9b472a6c72 | ||
|
|
1ead14589e | ||
|
|
b13065b1b5 | ||
|
|
a6581ee66b | ||
|
|
0dafa7ee42 | ||
|
|
908b91079b | ||
|
|
fce6ff317e | ||
|
|
fd50b11523 | ||
|
|
9090b8273c | ||
|
|
bfae1ab86c | ||
|
|
88882b523f | ||
|
|
382e3dc3ab | ||
|
|
f7bfcdd7aa | ||
|
|
2e41a26785 | ||
|
|
f3378f0ac1 | ||
|
|
12ee73d6a9 | ||
|
|
503baf52ed | ||
|
|
2deb75052c | ||
|
|
290dca3d67 | ||
|
|
f283a257d2 | ||
|
|
3d86f3a4e1 | ||
|
|
dc5a8069a9 | ||
|
|
4f31b90665 | ||
|
|
5d8c573357 | ||
|
|
6e1e5ccd84 | ||
|
|
f2d9fd1d1f | ||
|
|
97c8cbdaf5 | ||
|
|
05ceb5ae79 | ||
|
|
96cfdb260a | ||
|
|
0fec125688 | ||
|
|
a6d38c1ec0 | ||
|
|
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 | ||
|
|
1148d01c70 | ||
|
|
17d78553ff | ||
|
|
4c12dad51f |
@@ -2,19 +2,24 @@ version: 2.1
|
||||
|
||||
jobs:
|
||||
test_suite:
|
||||
environment:
|
||||
- GOPATH: /home/circleci/go
|
||||
docker:
|
||||
- image: circleci/golang:1.9
|
||||
- image: cimg/go:1.16
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
g++ --version
|
||||
cd tests/
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_toml_test.cpp -o check_toml_test
|
||||
go get github.com/BurntSushi/toml-test
|
||||
$GOPATH/bin/toml-test ./check_toml_test
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test
|
||||
export PATH=$(pwd):${PATH}
|
||||
git clone --depth 1 --branch v1.3.0 https://github.com/BurntSushi/toml-test.git
|
||||
cd toml-test/
|
||||
go install -v ./cmd/toml-test
|
||||
cd -
|
||||
toml-test check_toml_test
|
||||
# go clean -modcache
|
||||
# go get github.com/BurntSushi/toml-test/cmd/toml-test
|
||||
# $GOPATH/bin/toml-test ./check_toml_test
|
||||
test_serialization:
|
||||
docker:
|
||||
- image: circleci/buildpack-deps:bionic
|
||||
@@ -24,7 +29,7 @@ jobs:
|
||||
command: |
|
||||
g++ --version
|
||||
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 -I../ check_serialization.cpp -o check_serialization
|
||||
git clone https://github.com/BurntSushi/toml-test.git
|
||||
cp check_serialization toml-test/tests/valid
|
||||
cd toml-test/tests/valid
|
||||
@@ -47,7 +52,7 @@ jobs:
|
||||
command: |
|
||||
g++ --version
|
||||
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 -I../ check.cpp -o check
|
||||
git clone https://github.com/BurntSushi/toml-test.git
|
||||
cp check toml-test/tests/invalid
|
||||
cp check toml-test/tests/valid
|
||||
|
||||
6
.clusterfuzzlite/Dockerfile
Normal file
6
.clusterfuzzlite/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM gcr.io/oss-fuzz-base/base-builder
|
||||
RUN apt-get update && apt-get install -y make autoconf automake libtool
|
||||
|
||||
COPY . $SRC/toml11
|
||||
COPY .clusterfuzzlite/build.sh $SRC/build.sh
|
||||
WORKDIR $SRC/toml11
|
||||
3
.clusterfuzzlite/README.md
Normal file
3
.clusterfuzzlite/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# ClusterFuzzLite set up
|
||||
|
||||
This folder contains a fuzzing set for [ClusterFuzzLite](https://google.github.io/clusterfuzzlite).
|
||||
6
.clusterfuzzlite/build.sh
Normal file
6
.clusterfuzzlite/build.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash -eu
|
||||
# Copy fuzzer executable to $OUT/
|
||||
$CXX $CFLAGS $LIB_FUZZING_ENGINE \
|
||||
$SRC/toml11/.clusterfuzzlite/parse_fuzzer.cpp \
|
||||
-o $OUT/parse_fuzzer \
|
||||
-I$SRC/toml11/
|
||||
16
.clusterfuzzlite/parse_fuzzer.cpp
Normal file
16
.clusterfuzzlite/parse_fuzzer.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
#include <toml.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
std::string s(reinterpret_cast<const char *>(data), size);
|
||||
std::istringstream iss(s);
|
||||
try {
|
||||
const auto ref = toml::parse(iss);
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
.clusterfuzzlite/project.yaml
Normal file
1
.clusterfuzzlite/project.yaml
Normal file
@@ -0,0 +1 @@
|
||||
language: c++
|
||||
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
|
||||
[CMakeLists.txt]
|
||||
indent_size = 4
|
||||
|
||||
[*.{c,h}*]
|
||||
indent_size = 4
|
||||
|
||||
[*.{md,yml}]
|
||||
indent_size = 2
|
||||
30
.github/workflows/cflite_pr.yml
vendored
Normal file
30
.github/workflows/cflite_pr.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: ClusterFuzzLite PR fuzzing
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
permissions: read-all
|
||||
jobs:
|
||||
PR:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sanitizer: [address]
|
||||
steps:
|
||||
- name: Build Fuzzers (${{ matrix.sanitizer }})
|
||||
id: build
|
||||
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
|
||||
with:
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
language: c++
|
||||
bad-build-check: false
|
||||
- name: Run Fuzzers (${{ matrix.sanitizer }})
|
||||
id: run
|
||||
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
fuzz-seconds: 240
|
||||
mode: 'code-change'
|
||||
report-unreproducible-crashes: false
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
256
.github/workflows/main.yml
vendored
Normal file
256
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
name: build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build-linux-gcc:
|
||||
runs-on: Ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['g++-12', 'g++-11', 'g++-10', 'g++-9']
|
||||
standard: ['11', '14', '17', '20']
|
||||
unreleased: ['ON', 'OFF']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install
|
||||
run: |
|
||||
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get install libboost-test-dev
|
||||
sudo apt-get install language-pack-fr # test serializer w/ locale
|
||||
sudo apt-get install ${{ matrix.compiler }}
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
- name: Build
|
||||
run: |
|
||||
cd build && cmake --build .
|
||||
- name: Test
|
||||
run: |
|
||||
cd build && ctest --output-on-failure
|
||||
build-linux-clang:
|
||||
runs-on: Ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['15', '14', '13', '12', '11']
|
||||
standard: ['11', '14', '17', '20']
|
||||
unreleased: ['ON', 'OFF']
|
||||
exclude:
|
||||
- {compiler: '14', standard: '20'} # to avoid using gcc-13 libstdc++
|
||||
- {compiler: '13', standard: '20'} # with older clang
|
||||
- {compiler: '12', standard: '20'}
|
||||
- {compiler: '11', standard: '20'}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install
|
||||
run: |
|
||||
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get install libboost-test-dev
|
||||
sudo apt-get install language-pack-fr # test serializer w/ locale
|
||||
sudo apt-get install clang-${{ matrix.compiler }}
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_C_COMPILER=clang-${{ matrix.compiler }} -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
- name: Build
|
||||
run: |
|
||||
cd build && cmake --build .
|
||||
- name: Test
|
||||
run: |
|
||||
cd build && ctest --output-on-failure
|
||||
|
||||
build-linux-old-gcc:
|
||||
runs-on: Ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['g++-8', 'g++-7']
|
||||
standard: ['11', '14', '17', '20']
|
||||
unreleased: ['ON', 'OFF']
|
||||
exclude:
|
||||
- {compiler: 'g++-7', standard: '20'}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install
|
||||
run: |
|
||||
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get install libboost-test-dev
|
||||
sudo apt-get install language-pack-fr # test serializer w/ locale
|
||||
sudo apt-get install ${{ matrix.compiler }}
|
||||
- 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 -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
else
|
||||
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
fi
|
||||
- name: Build
|
||||
run: |
|
||||
cd build && cmake --build .
|
||||
- name: Test
|
||||
run: |
|
||||
cd build && ctest --output-on-failure
|
||||
|
||||
build-linux-old-clang:
|
||||
runs-on: Ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: ['10', '9', '8', '7', '6.0']
|
||||
standard: ['11', '14', '17', '20']
|
||||
unreleased: ['ON', 'OFF']
|
||||
exclude:
|
||||
- {compiler: '6.0', standard: '20'}
|
||||
- {compiler: '7', standard: '20'}
|
||||
- {compiler: '8', standard: '20'}
|
||||
- {compiler: '9', standard: '20'}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install
|
||||
run: |
|
||||
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get install libboost-test-dev
|
||||
sudo apt-get install language-pack-fr # test serializer w/ locale
|
||||
sudo apt-get install clang-${{ matrix.compiler }}
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_C_COMPILER=clang-${{ matrix.compiler }} -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
- name: Build
|
||||
run: |
|
||||
cd build && cmake --build .
|
||||
- name: Test
|
||||
run: |
|
||||
cd build && ctest --output-on-failure
|
||||
|
||||
# build-osx-13-arm64:
|
||||
# runs-on: macos-13-arm64
|
||||
# strategy:
|
||||
# matrix:
|
||||
# standard: ['11', '14', '17', '20']
|
||||
# unreleased: ['ON', 'OFF']
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v4
|
||||
# with:
|
||||
# submodules: true
|
||||
# - name: Install
|
||||
# run: |
|
||||
# brew install boost
|
||||
# - name: Configure
|
||||
# run: |
|
||||
# mkdir build && cd build
|
||||
# cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
# - name: Build
|
||||
# run: |
|
||||
# cd build && cmake --build .
|
||||
# - name: Test
|
||||
# run: |
|
||||
# cd build && ctest --output-on-failure
|
||||
|
||||
build-osx-13:
|
||||
runs-on: macos-13
|
||||
strategy:
|
||||
matrix:
|
||||
standard: ['11', '14', '17', '20']
|
||||
unreleased: ['ON', 'OFF']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install
|
||||
run: |
|
||||
brew install boost
|
||||
env:
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
- name: Build
|
||||
run: |
|
||||
cd build && cmake --build .
|
||||
- name: Test
|
||||
run: |
|
||||
cd build && ctest --output-on-failure
|
||||
|
||||
build-osx-12:
|
||||
runs-on: macos-12
|
||||
strategy:
|
||||
matrix:
|
||||
standard: ['11', '14', '17', '20']
|
||||
unreleased: ['ON', 'OFF']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install
|
||||
run: |
|
||||
brew install boost
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
- name: Build
|
||||
run: |
|
||||
cd build && cmake --build .
|
||||
- name: Test
|
||||
run: |
|
||||
cd build && ctest --output-on-failure
|
||||
|
||||
build-windows-msvc:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
matrix:
|
||||
standard: ['11', '14', '17', '20']
|
||||
config: ['Release', 'Debug']
|
||||
unreleased: ['ON', 'OFF']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install
|
||||
run: |
|
||||
(New-Object System.Net.WebClient).DownloadFile("https://github.com/actions/boost-versions/releases/download/1.72.0-20200608.4/boost-1.72.0-win32-msvc14.2-x86_64.tar.gz", "$env:TEMP\\boost.tar.gz")
|
||||
7z.exe x "$env:TEMP\\boost.tar.gz" -o"$env:TEMP\\boostArchive" -y | Out-Null
|
||||
7z.exe x "$env:TEMP\\boostArchive" -o"$env:TEMP\\boost" -y | Out-Null
|
||||
Push-Location -Path "$env:TEMP\\boost"
|
||||
Invoke-Expression .\\setup.ps1
|
||||
- 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_NO_BOOST_CMAKE=ON -DBOOST_ROOT="C:\\hostedtoolcache\\windows\\Boost\\1.72.0\\x86_64" -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
|
||||
- name: Build
|
||||
working-directory: ./build
|
||||
run: |
|
||||
cmake --build . --config "${{ matrix.config }}"
|
||||
- name: Test
|
||||
working-directory: ./build
|
||||
run: |
|
||||
file --mime-encoding tests/toml/tests/example.toml
|
||||
file --mime-encoding tests/toml/tests/fruit.toml
|
||||
file --mime-encoding tests/toml/tests/hard_example.toml
|
||||
file --mime-encoding tests/toml/tests/hard_example_unicode.toml
|
||||
ctest --build-config "${{ matrix.config }}" --output-on-failure
|
||||
250
.travis.yml
250
.travis.yml
@@ -1,250 +0,0 @@
|
||||
dist: trusty
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-5" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-5
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-6" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-6
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-7" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-7
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-8" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
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=11 TOML_HEAD=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=OFF
|
||||
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
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-8
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-3.9" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-3.9
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-3.9
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-4.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-4.0
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-4.0
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-5.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-5.0
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-6.0" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-6.0
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-6.0
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-7" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-7
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-8" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-8
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-8" CXX_STANDARD=11 TOML_HEAD=ON
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-8
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-8" CXX_STANDARD=17 TOML_HEAD=OFF
|
||||
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
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- clang-8
|
||||
- g++-8
|
||||
- boost1.70
|
||||
- os: osx
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: CXX_STANDARD=11
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/Library/Caches/Homebrew
|
||||
addons:
|
||||
homebrew:
|
||||
update: true
|
||||
packages:
|
||||
- cmake
|
||||
- boost
|
||||
|
||||
script:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
mkdir -p cmake
|
||||
travis_retry wget "https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz"
|
||||
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
||||
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
||||
fi
|
||||
- cmake --version
|
||||
- mkdir build
|
||||
- cd build
|
||||
- git clone https://github.com/toml-lang/toml.git
|
||||
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} ..
|
||||
- make
|
||||
- ctest --output-on-failure
|
||||
|
||||
# https://stackoverflow.com/a/53331571
|
||||
before_cache:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
brew cleanup
|
||||
fi
|
||||
114
CMakeLists.txt
114
CMakeLists.txt
@@ -1,46 +1,26 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
enable_testing()
|
||||
|
||||
project(toml11)
|
||||
project(toml11 VERSION 3.8.1)
|
||||
|
||||
set(toml11_VERSION_MAYOR 3)
|
||||
set(toml11_VERSION_MINOR 2)
|
||||
set(toml11_VERSION_PATCH 0)
|
||||
set(toml11_VERSION
|
||||
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
||||
)
|
||||
option(toml11_BUILD_TEST "Build toml tests" OFF)
|
||||
option(toml11_INSTALL "Install CMake targets during install step." ON)
|
||||
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
|
||||
option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF)
|
||||
|
||||
option(toml11_BUILD_TEST "Build toml tests" ON)
|
||||
option(TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
"use features in toml-lang/toml master while testing" OFF)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
set(CXX_STANDARD_REQUIRED ON)
|
||||
else()
|
||||
# Manually check for C++11 compiler flag.
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=gnu++11" COMPILER_SUPPORTS_GNU11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" COMPILER_SUPPORTS_GNU0X)
|
||||
if(COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXXOX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
elseif(COMPILER_SUPPORTS_GNU11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
|
||||
elseif(COMPILER_SUPPORTS_GNU0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
|
||||
if(MSVC)
|
||||
# add_definitions("/Zc:__cplusplus") # define __cplusplus value correctly
|
||||
add_definitions("/utf-8") # enable to use u8"" literal
|
||||
if(MSVC_VERSION LESS 1910)
|
||||
message(STATUS "MSVC < 1910. DEFINE_CONVERSION_NON_INTRUSIVE is disabled")
|
||||
add_definitions(-DTOML11_WITHOUT_DEFINE_NON_INTRUSIVE)
|
||||
elseif(MSVC_VERSION LESS 1920)
|
||||
add_definitions("/experimental:preprocessor") # MSVC 2017
|
||||
else()
|
||||
if(MSVC)
|
||||
if(MSVC_VERSION LESS 1900)
|
||||
message(SEND_ERROR "MSVC < 14.0 is not supported. Please update your compiler or use mingw")
|
||||
endif()
|
||||
else()
|
||||
message(SEND_ERROR "The ${CMAKE_CXX_COMPILER} compiler lacks C++11 support. Use another compiler.")
|
||||
endif()
|
||||
add_definitions("/Zc:preprocessor") # MSVC 2019
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -67,38 +47,40 @@ write_basic_package_version_file(
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
cmake/toml11Config.cmake.in
|
||||
${toml11_config}
|
||||
INSTALL_DESTINATION ${toml11_install_cmake_dir}
|
||||
PATH_VARS toml11_install_cmake_dir
|
||||
)
|
||||
if (toml11_INSTALL)
|
||||
configure_package_config_file(
|
||||
cmake/toml11Config.cmake.in
|
||||
${toml11_config}
|
||||
INSTALL_DESTINATION ${toml11_install_cmake_dir}
|
||||
PATH_VARS toml11_install_cmake_dir
|
||||
)
|
||||
|
||||
# Install config files
|
||||
install(FILES ${toml11_config} ${toml11_config_version}
|
||||
DESTINATION ${toml11_install_cmake_dir}
|
||||
)
|
||||
# Install config files
|
||||
install(FILES ${toml11_config} ${toml11_config_version}
|
||||
DESTINATION ${toml11_install_cmake_dir}
|
||||
)
|
||||
|
||||
# Install header files
|
||||
install(
|
||||
FILES toml.hpp
|
||||
DESTINATION "${toml11_install_include_dir}"
|
||||
)
|
||||
install(
|
||||
DIRECTORY "toml"
|
||||
DESTINATION "${toml11_install_include_dir}"
|
||||
FILES_MATCHING PATTERN "*.hpp"
|
||||
)
|
||||
# Install header files
|
||||
install(
|
||||
FILES toml.hpp
|
||||
DESTINATION "${toml11_install_include_dir}"
|
||||
)
|
||||
install(
|
||||
DIRECTORY "toml"
|
||||
DESTINATION "${toml11_install_include_dir}"
|
||||
FILES_MATCHING PATTERN "*.hpp"
|
||||
)
|
||||
|
||||
# Export targets and install them
|
||||
install(TARGETS toml11
|
||||
EXPORT toml11Targets
|
||||
)
|
||||
install(EXPORT toml11Targets
|
||||
FILE toml11Targets.cmake
|
||||
DESTINATION ${toml11_install_cmake_dir}
|
||||
NAMESPACE toml11::
|
||||
)
|
||||
# Export targets and install them
|
||||
install(TARGETS toml11
|
||||
EXPORT toml11Targets
|
||||
)
|
||||
install(EXPORT toml11Targets
|
||||
FILE toml11Targets.cmake
|
||||
DESTINATION ${toml11_install_cmake_dir}
|
||||
NAMESPACE toml11::
|
||||
)
|
||||
endif()
|
||||
|
||||
if (toml11_BUILD_TEST)
|
||||
add_subdirectory(tests)
|
||||
|
||||
505
README.md
505
README.md
@@ -1,23 +1,23 @@
|
||||
toml11
|
||||
======
|
||||
|
||||
[](https://travis-ci.org/ToruNiina/toml11)
|
||||
[](https://github.com/ToruNiina/toml11/actions)
|
||||
[](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master)
|
||||
[](https://circleci.com/gh/ToruNiina/toml11/tree/master)
|
||||
[](https://github.com/ToruNiina/toml11/releases)
|
||||
[](LICENSE)
|
||||
[](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
|
||||
[TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md)
|
||||
after version 2.0.0.
|
||||
|
||||
It passes [the language agnostic test suite for TOML parsers by BurntSushi](https://github.com/BurntSushi/toml-test).
|
||||
Not only the test suite itself, a TOML reader/encoder also runs on [CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||
You can see the error messages about invalid files and serialization results of valid files at
|
||||
[CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||
- It is compatible to the latest version of [TOML v1.0.0](https://toml.io/en/v1.0.0).
|
||||
- It is one of the most TOML standard compliant libraries, tested with [the language agnostic test suite for TOML parsers by BurntSushi](https://github.com/BurntSushi/toml-test).
|
||||
- It shows highly informative error messages. You can see the error messages about invalid files at [CircleCI](https://circleci.com/gh/ToruNiina/toml11).
|
||||
- It has configurable container. You can use any random-access containers and key-value maps as backend containers.
|
||||
- It optionally preserves comments without any overhead.
|
||||
- It has configurable serializer that supports comments, inline tables, literal strings and multiline strings.
|
||||
- It supports user-defined type conversion from/into toml values.
|
||||
- It correctly handles UTF-8 sequences, with or without BOM, both on posix and Windows.
|
||||
|
||||
## Example
|
||||
|
||||
@@ -27,15 +27,29 @@ You can see the error messages about invalid files and serialization results of
|
||||
|
||||
int main()
|
||||
{
|
||||
const auto data = toml::parse("example.toml");
|
||||
|
||||
// ```toml
|
||||
// title = "an example toml file"
|
||||
std::string title = toml::find<std::string>(data, "title");
|
||||
std::cout << "the title is " << title << std::endl;
|
||||
// nums = [3, 1, 4, 1, 5]
|
||||
// ```
|
||||
auto data = toml::parse("example.toml");
|
||||
|
||||
// nums = [1, 2, 3, 4, 5]
|
||||
std::vector<int> nums = toml::find<std::vector<int>>(data, "nums");
|
||||
std::cout << "the length of `nums` is" << nums.size() << std::endl;
|
||||
// find a value with the specified type from a table
|
||||
std::string title = toml::find<std::string>(data, "title");
|
||||
|
||||
// convert the whole array into any container automatically
|
||||
std::vector<int> nums = toml::find<std::vector<int>>(data, "nums");
|
||||
|
||||
// access with STL-like manner
|
||||
if(!data.contains("foo"))
|
||||
{
|
||||
data["foo"] = "bar";
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -84,7 +98,7 @@ int main()
|
||||
Just include the file after adding it to the include path.
|
||||
|
||||
```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>
|
||||
|
||||
int main()
|
||||
@@ -99,6 +113,39 @@ int main()
|
||||
The convenient way is to add this repository as a git-submodule or to install
|
||||
it in your system by CMake.
|
||||
|
||||
Note for MSVC: We recommend to set `/Zc:__cplusplus` to detect C++ version correctly.
|
||||
|
||||
### Example installation
|
||||
|
||||
For local installation build & use the provided install target
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ToruNiina/toml11.git
|
||||
mkdir -p toml11/build
|
||||
cd toml11/build
|
||||
cmake .. -DCMAKE_CXX_STANDARD=11
|
||||
sudo make install
|
||||
```
|
||||
|
||||
In case you want to create a `.deb` you can use `checkinstall`.
|
||||
```bash
|
||||
sudo checkinstall
|
||||
[[ .. skipping for clarity ]]
|
||||
**********************************************************************
|
||||
|
||||
Done. The new package has been installed and saved to
|
||||
|
||||
/home/user/toml11/build/build_20230728-1_amd64.deb
|
||||
|
||||
You can remove it from your system anytime using:
|
||||
|
||||
dpkg -r build
|
||||
|
||||
**********************************************************************
|
||||
```
|
||||
|
||||
You should get a package that you can install with `dpkg -i <myfile>.deb` and remove with `dpkg -r <myfile>.deb`
|
||||
|
||||
## Decoding a toml file
|
||||
|
||||
To parse a toml file, the only thing you have to do is
|
||||
@@ -109,6 +156,9 @@ const std::string fname("sample.toml");
|
||||
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`.
|
||||
|
||||
You can also pass a `std::istream` to the `toml::parse` function.
|
||||
@@ -166,7 +216,7 @@ what(): [error] bad time: should be HH:MM:SS.subsec
|
||||
--> ./datetime-malformed-no-secs.toml
|
||||
1 | no-secs = 1987-07-05T17:45Z
|
||||
| ^------- HH:MM:SS.subsec
|
||||
|
|
||||
|
|
||||
Hint: pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999
|
||||
Hint: fail: 1979-05-27T7:32:00, 1979-05-27 17:32
|
||||
```
|
||||
@@ -231,7 +281,7 @@ See also [underlying types](#underlying-types).
|
||||
**NOTE**: For some technical reason, automatic conversion between `integer` and
|
||||
`floating` is not supported. If you want to get a floating value even if a value
|
||||
has integer value, you need to convert it manually after obtaining a value,
|
||||
like the followings.
|
||||
like the following.
|
||||
|
||||
```cpp
|
||||
const auto vx = toml::find(data, "x");
|
||||
@@ -256,11 +306,11 @@ shape = "round"
|
||||
``` cpp
|
||||
const auto data = toml::parse("fruit.toml");
|
||||
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 color = toml::find<std::string>(fruit, "color");
|
||||
const auto shape = toml::find<std::string>(fruit, "shape");
|
||||
const auto color = toml::find<std::string>(physical, "color");
|
||||
const auto shape = toml::find<std::string>(physical, "shape");
|
||||
```
|
||||
|
||||
Here, variable `fruit` is a `toml::value` and can be used as the first argument
|
||||
@@ -274,10 +324,44 @@ const auto color = toml::find<std::string>(data, "fruit", "physical", "color");
|
||||
const auto shape = toml::find<std::string>(data, "fruit", "physical", "shape");
|
||||
```
|
||||
|
||||
### Finding a value in an array
|
||||
|
||||
You can find n-th value in an array by `toml::find`.
|
||||
|
||||
```toml
|
||||
values = ["foo", "bar", "baz"]
|
||||
```
|
||||
|
||||
``` cpp
|
||||
const auto data = toml::parse("sample.toml");
|
||||
const auto values = toml::find(data, "values");
|
||||
const auto bar = toml::find<std::string>(values, 1);
|
||||
```
|
||||
|
||||
`toml::find` can also search array recursively.
|
||||
|
||||
```cpp
|
||||
const auto data = toml::parse("fruit.toml");
|
||||
const auto bar = toml::find<std::string>(data, "values", 1);
|
||||
```
|
||||
|
||||
Before calling `toml::find`, you can check if a value corresponding to a key
|
||||
exists. You can use both `bool toml::value::contains(const key&) const` and
|
||||
`std::size_t toml::value::count(const key&) const`. Those behaves like the
|
||||
`std::map::contains` and `std::map::count`.
|
||||
|
||||
```cpp
|
||||
const auto data = toml::parse("fruit.toml");
|
||||
if(data.contains("fruit") && data.at("fruit").count("physical") != 0)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### In case of error
|
||||
|
||||
If the value does not exist, `toml::find` throws an error with the location of
|
||||
the table.
|
||||
If the value does not exist, `toml::find` throws `std::out_of_range` with the
|
||||
location of the table.
|
||||
|
||||
```console
|
||||
terminate called after throwing an instance of 'std::out_of_range'
|
||||
@@ -287,11 +371,6 @@ terminate called after throwing an instance of 'std::out_of_range'
|
||||
| ~~~~~ in this table
|
||||
```
|
||||
|
||||
**Note**: It is recommended to find a table as `toml::value` because it has much information
|
||||
compared to `toml::table`, which is an alias of
|
||||
`std::unordered_map<std::string, toml::value>`. Since `toml::table` does not have
|
||||
any information about toml file, such as where the table was defined in the file.
|
||||
|
||||
----
|
||||
|
||||
If the specified type differs from the actual value contained, it throws
|
||||
@@ -423,6 +502,29 @@ if(answer.is_integer() && answer.as_integer(std::nothrow) == 42)
|
||||
|
||||
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& kv : data.as_table())
|
||||
{
|
||||
std::cout << kv.first << '\n';
|
||||
}
|
||||
for(const auto& [k, v] : data.as_table()) // or in C++17
|
||||
{
|
||||
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.
|
||||
|
||||
```cpp
|
||||
@@ -768,6 +870,19 @@ const auto data = toml::parse("example.toml");
|
||||
const auto num = toml::find_or(data, "num", 42);
|
||||
```
|
||||
|
||||
It works recursively if you pass several keys for subtables.
|
||||
In that case, the last argument is considered to be the optional value.
|
||||
All other arguments between `toml::value` and the optional value are considered as keys.
|
||||
|
||||
```cpp
|
||||
// [fruit.physical]
|
||||
// color = "red"
|
||||
auto data = toml::parse("fruit.toml");
|
||||
auto color = toml::find_or(data, "fruit", "physical", "color", "red");
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^
|
||||
// arguments optional value
|
||||
```
|
||||
|
||||
Also, `toml::get_or` returns a default value if `toml::get<T>` failed.
|
||||
|
||||
```cpp
|
||||
@@ -825,7 +940,7 @@ toml::visit([](const auto& val) -> void {
|
||||
```
|
||||
|
||||
The function object that would be passed to `toml::visit` must be able to
|
||||
recieve all the possible TOML types. Also, the result types should be the same
|
||||
receive all the possible TOML types. Also, the result types should be the same
|
||||
each other.
|
||||
|
||||
## Constructing a toml::value
|
||||
@@ -869,24 +984,50 @@ toml::value v(toml::local_time(std::chrono::hours(10)));
|
||||
```
|
||||
|
||||
You can construct an array object not only from `initializer_list`, but also
|
||||
from STL containers.
|
||||
from STL containers. In that case, the element type must be convertible to
|
||||
`toml::value`.
|
||||
|
||||
```cpp
|
||||
std::vector<int> vec{1,2,3,4,5};
|
||||
toml::value v = vec;
|
||||
toml::value v(vec);
|
||||
```
|
||||
|
||||
All the elements of `initializer_list` should be convertible into `toml::value`.
|
||||
When you construct an array value, all the elements of `initializer_list`
|
||||
must be convertible into `toml::value`.
|
||||
|
||||
If a `toml::value` has an array, you can `push_back` an element in it.
|
||||
|
||||
```cpp
|
||||
toml::value v{1,2,3,4,5};
|
||||
v.push_back(6);
|
||||
```
|
||||
|
||||
`emplace_back` also works.
|
||||
|
||||
## Preserving comments
|
||||
|
||||
After toml11 v3, you can choose whether comments are preserved or not.
|
||||
toml11 v3 or later allows you yo choose whether comments are preserved or not via template parameter
|
||||
|
||||
```cpp
|
||||
const auto data1 = toml::parse<toml::discard_comments >("example.toml");
|
||||
const auto data2 = toml::parse<toml::preserve_comments>("example.toml");
|
||||
```
|
||||
|
||||
or macro definition.
|
||||
|
||||
```cpp
|
||||
#define TOML11_PRESERVE_COMMENTS_BY_DEFAULT
|
||||
#include <toml11/toml.hpp>
|
||||
```
|
||||
|
||||
This feature is controlled by template parameter in `toml::basic_value<...>`.
|
||||
`toml::value` is an alias of `toml::basic_value<...>`.
|
||||
|
||||
If template parameter is explicitly specified, the return value of `toml::parse`
|
||||
will be `toml::basic_value<toml::preserve_comments>`.
|
||||
If the macro is defined, the alias `toml::value` will be
|
||||
`toml::basic_value<toml::preserve_comments>`.
|
||||
|
||||
Comments related to a value can be obtained by `toml::value::comments()`.
|
||||
The return value has the same interface as `std::vector<std::string>`.
|
||||
|
||||
@@ -1063,7 +1204,7 @@ add a comma after the first element (like `[1,]`).
|
||||
"[[table]]"_toml; // This is a table that has an array of tables inside.
|
||||
|
||||
"[[1]]"_toml; // This literal is ambiguous.
|
||||
// Currently, it becomes a table that has array of table "1".
|
||||
// Currently, it becomes an empty array of table named "1".
|
||||
"1 = [{}]"_toml; // This is a table that has an array of table named 1.
|
||||
"[[1,]]"_toml; // This is an array of arrays.
|
||||
"[[1],]"_toml; // ditto.
|
||||
@@ -1093,7 +1234,7 @@ const auto data = toml::parse("example.toml");
|
||||
const foo f = toml::find<ext::foo>(data, "foo");
|
||||
```
|
||||
|
||||
There are 2 ways to use `toml::get` with the types that you defined.
|
||||
There are 3 ways to use `toml::get` with the types that you defined.
|
||||
|
||||
The first one is to implement `from_toml(const toml::value&)` member function.
|
||||
|
||||
@@ -1120,7 +1261,31 @@ struct foo
|
||||
In this way, because `toml::get` first constructs `foo` without arguments,
|
||||
the type should be default-constructible.
|
||||
|
||||
The second is to implement specialization of `toml::from` for your type.
|
||||
The second is to implement `constructor(const toml::value&)`.
|
||||
|
||||
```cpp
|
||||
namespace ext
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
explicit foo(const toml::value& v)
|
||||
: a(toml::find<int>(v, "a")), b(toml::find<double>(v, "b")),
|
||||
c(toml::find<std::string>(v, "c"))
|
||||
{}
|
||||
|
||||
int a;
|
||||
double b;
|
||||
std::string c;
|
||||
};
|
||||
} // ext
|
||||
```
|
||||
|
||||
Note that implicit default constructor declaration will be suppressed
|
||||
when a constructor is defined. If you want to use the struct (here, `foo`)
|
||||
in a container (e.g. `std::vector<foo>`), you may need to define default
|
||||
constructor explicitly.
|
||||
|
||||
The third is to implement specialization of `toml::from` for your type.
|
||||
|
||||
```cpp
|
||||
namespace ext
|
||||
@@ -1153,8 +1318,16 @@ struct from<ext::foo>
|
||||
In this way, since the conversion function is defined outside of the class,
|
||||
you can add conversion between `toml::value` and classes defined in another library.
|
||||
|
||||
Note that you cannot implement both of the functions because the overload
|
||||
resolution of `toml::get` will be ambiguous.
|
||||
In some cases, a class has a templatized constructor that takes a template, `T`.
|
||||
It confuses `toml::get/find<T>` because it makes the class "constructible" from
|
||||
`toml::value`. To avoid this problem, `toml::from` and `from_toml` always
|
||||
precede constructor. It makes easier to implement conversion between
|
||||
`toml::value` and types defined in other libraries because it skips constructor.
|
||||
|
||||
But, importantly, you cannot define `toml::from<T>` and `T.from_toml` at the same
|
||||
time because it causes ambiguity in the overload resolution of `toml::get<T>` and `toml::find<T>`.
|
||||
|
||||
So the precedence is `toml::from<T>` == `T.from_toml()` > `T(toml::value)`.
|
||||
|
||||
If you want to convert any versions of `toml::basic_value`,
|
||||
you need to templatize the conversion function as follows.
|
||||
@@ -1205,9 +1378,9 @@ struct foo
|
||||
double b;
|
||||
std::string c;
|
||||
|
||||
toml::table into_toml() const // you need to mark it const.
|
||||
toml::value into_toml() const // you need to mark it const.
|
||||
{
|
||||
return toml::table{{"a", this->a}, {"b", this->b}, {"c", this->c}};
|
||||
return toml::value{{"a", this->a}, {"b", this->b}, {"c", this->c}};
|
||||
}
|
||||
};
|
||||
} // ext
|
||||
@@ -1234,9 +1407,9 @@ namespace toml
|
||||
template<>
|
||||
struct into<ext::foo>
|
||||
{
|
||||
static toml::table into_toml(const ext::foo& f)
|
||||
static toml::value into_toml(const ext::foo& f)
|
||||
{
|
||||
return toml::table{{"a", f.a}, {"b", f.b}, {"c", f.c}};
|
||||
return toml::value{{"a", f.a}, {"b", f.b}, {"c", f.c}};
|
||||
}
|
||||
};
|
||||
} // toml
|
||||
@@ -1248,6 +1421,55 @@ toml::value v(f);
|
||||
Any type that can be converted to `toml::value`, e.g. `int`, `toml::table` and
|
||||
`toml::array` are okay to return from `into_toml`.
|
||||
|
||||
You can also return a custom `toml::basic_value` from `toml::into`.
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<>
|
||||
struct into<ext::foo>
|
||||
{
|
||||
static toml::basic_value<toml::preserve_comments> into_toml(const ext::foo& f)
|
||||
{
|
||||
toml::basic_value<toml::preserve_comments> v{{"a", f.a}, {"b", f.b}, {"c", f.c}};
|
||||
v.comments().push_back(" comment");
|
||||
return v;
|
||||
}
|
||||
};
|
||||
} // toml
|
||||
```
|
||||
|
||||
But note that, if this `basic_value` would be assigned into other `toml::value`
|
||||
that discards `comments`, the comments would be dropped.
|
||||
|
||||
### Macro to automatically define conversion functions
|
||||
|
||||
There is a helper macro that automatically generates conversion functions `from` and `into` for a simple struct.
|
||||
|
||||
```cpp
|
||||
namespace foo
|
||||
{
|
||||
struct Foo
|
||||
{
|
||||
std::string s;
|
||||
double d;
|
||||
int i;
|
||||
};
|
||||
} // foo
|
||||
|
||||
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
|
||||
|
||||
int main()
|
||||
{
|
||||
const auto file = toml::parse("example.toml");
|
||||
auto f = toml::find<foo::Foo>(file, "foo");
|
||||
}
|
||||
```
|
||||
|
||||
And then you can use `toml::find<foo::Foo>(file, "foo");`
|
||||
|
||||
**Note** that, because of a slight difference in implementation of preprocessor between gcc/clang and MSVC, [you need to define `/Zc:preprocessor`](https://github.com/ToruNiina/toml11/issues/139#issuecomment-803683682) to use it in MSVC (Thank you @glebm !).
|
||||
|
||||
## Formatting user-defined error messages
|
||||
|
||||
When you encounter an error after you read the toml value, you may want to
|
||||
@@ -1349,7 +1571,7 @@ const toml::source_location loc = v.location();
|
||||
|
||||
## Exceptions
|
||||
|
||||
All the exceptions thrown by toml11 inherits `toml::exception` that inherits
|
||||
The following `exception` classes inherits `toml::exception` that inherits
|
||||
`std::exception`.
|
||||
|
||||
```cpp
|
||||
@@ -1376,6 +1598,16 @@ struct exception : public std::exception
|
||||
|
||||
It represents where the error occurs.
|
||||
|
||||
`syntax_error` will be thrown from `toml::parse` and `_toml` literal.
|
||||
`type_error` will be thrown from `toml::get/find`, `toml::value::as_xxx()`, and
|
||||
other functions that takes a content inside of `toml::value`.
|
||||
|
||||
Note that, currently, from `toml::value::at()` and `toml::find(value, key)`
|
||||
may throw an `std::out_of_range` that does not inherits `toml::exception`.
|
||||
|
||||
Also, in some cases, most likely in the file open error, it will throw an
|
||||
`std::runtime_error`.
|
||||
|
||||
## Colorize Error Messages
|
||||
|
||||
By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from
|
||||
@@ -1421,7 +1653,7 @@ it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code).
|
||||
Without `TOML11_COLORIZE_ERROR_MESSAGE`, you can still colorize user-defined
|
||||
error message by passing `true` to the `toml::format_error` function.
|
||||
If you define `TOML11_COLORIZE_ERROR_MESSAGE`, the value is `true` by default.
|
||||
If not, the defalut value would be `false`.
|
||||
If not, the default value would be `false`.
|
||||
|
||||
```cpp
|
||||
std::cerr << toml::format_error("[error] value should be positive",
|
||||
@@ -1429,10 +1661,62 @@ std::cerr << toml::format_error("[error] value should be positive",
|
||||
hints, /*colorize = */ true) << std::endl;
|
||||
```
|
||||
|
||||
Note: It colorize `[error]` in red. That means that it detects `[error]` prefix
|
||||
Note: It colorizes `[error]` in red. That means that it detects `[error]` prefix
|
||||
at the front of the error message. If there is no `[error]` prefix,
|
||||
`format_error` adds it to the error message.
|
||||
|
||||
Compared to the `TOML11_COLORIZE_ERROR_MESSAGE` macro that enables colorization
|
||||
statically, toml11 provides `toml::color::enable` & `toml::color::disable`
|
||||
functions to dynamically change the color mode. This feature overwrites
|
||||
`TOML11_COLORIZE_ERROR_MESSAGE` and the `colorize` argument of
|
||||
`toml::format_error` when you call `enable`.
|
||||
|
||||
Note: If either `TOML11_COLORIZE_ERROR_MESSAGE` is defined or the `colorize`
|
||||
argument is used, it takes precedence, meaning that `disable` won't work.
|
||||
Accordingly, we highly recommend using only one of them.
|
||||
|
||||
```cpp
|
||||
toml::color::enable(); // enable colorization
|
||||
toml::color::disable(); // disable colorization
|
||||
```
|
||||
|
||||
If you use user-defined error message, you can manage the setting as follows:
|
||||
|
||||
```cpp
|
||||
toml::color::enable();
|
||||
std::cerr << toml::format_error("[error] value should be positive",
|
||||
data.at("num"), "positive number required",
|
||||
hints) << std::endl; // colorized
|
||||
|
||||
toml::color::disable();
|
||||
std::cerr << toml::format_error("[error] value should be positive",
|
||||
data.at("num"), "positive number required",
|
||||
hints) << std::endl; // NOT colorized
|
||||
```
|
||||
|
||||
Or you may use toml11 in your application like:
|
||||
|
||||
```cpp
|
||||
std::vector<std::string> args(argv + 1, argv + argc);
|
||||
auto result = std::find(args.begin(), args.end(), "--color");
|
||||
if (result != args.end()) {
|
||||
toml::color::enable();
|
||||
} else {
|
||||
toml::color::disable();
|
||||
}
|
||||
|
||||
// use toml11 ...
|
||||
```
|
||||
|
||||
## Opting out of the default `[error]` prefix
|
||||
|
||||
toml11 prints error messages with the `[error]` prefix by default.
|
||||
Defining `TOML11_NO_ERROR_PREFIX` will let toml11 omit the prefix regardless of colorized or not in case you would use a custom prefix, such as `Error:`.
|
||||
|
||||
```cpp
|
||||
#define TOML11_NO_ERROR_PREFIX
|
||||
```
|
||||
|
||||
## Serializing TOML data
|
||||
|
||||
toml11 enables you to serialize data into toml format.
|
||||
@@ -1522,7 +1806,7 @@ const std::string fmt = toml::format(v);
|
||||
```
|
||||
|
||||
To control the width and precision, `toml::format` receives optional second and
|
||||
third arguments to set them. By default, the witdh is 80 and the precision is
|
||||
third arguments to set them. By default, the width is 80 and the precision is
|
||||
`std::numeric_limits<double>::max_digit10`.
|
||||
|
||||
```cpp
|
||||
@@ -1558,7 +1842,7 @@ flag that represents a kind of a string, `string_t::basic` and `string_t::litera
|
||||
Although `std::string` is not an exact toml type, still you can get a reference
|
||||
that points to internal `std::string` by using `toml::get<std::string>()` for convenience.
|
||||
The most important difference between `std::string` and `toml::string` is that
|
||||
`toml::string` will be formatted as a TOML string when outputed with `ostream`.
|
||||
`toml::string` will be formatted as a TOML string when outputted with `ostream`.
|
||||
This feature is introduced to make it easy to write a custom serializer.
|
||||
|
||||
`Datetime` variants are `struct` that are defined in this library.
|
||||
@@ -1567,26 +1851,18 @@ not capable of representing a Local Time independent from a specific day.
|
||||
|
||||
## Unreleased TOML features
|
||||
|
||||
There are some unreleased features in toml-lang/toml:master.
|
||||
Currently, the following features are available after defining
|
||||
`TOML11_USE_UNRELEASED_TOML_FEATURES` macro flag.
|
||||
After TOML v1.0.0 has been released, some features are added to the main branch
|
||||
of the TOML spec repository. (see: [CHANGELOG.md in toml-lang/toml repository](https://github.com/toml-lang/toml/blob/main/CHANGELOG.md)).
|
||||
|
||||
To use those features, `#define` `TOML11_USE_UNRELEASED_TOML_FEATURES` before
|
||||
including `toml.hpp` or pass `-DTOML11_USE_UNRELEASED_TOML_FEATURES` to your
|
||||
compiler.
|
||||
The following list shows available "unreleased" features that can be activated
|
||||
by defining a macro named `TOML11_USE_UNRELEASED_FEATURES`.
|
||||
|
||||
- Leading zeroes in exponent parts of floats are permitted.
|
||||
- e.g. `1.0e+01`, `5e+05`
|
||||
- [toml-lang/toml/PR/656](https://github.com/toml-lang/toml/pull/656)
|
||||
- Allow raw tab characters in basic strings and multi-line basic strings.
|
||||
- [toml-lang/toml/PR/627](https://github.com/toml-lang/toml/pull/627)
|
||||
- Allow heterogeneous arrays
|
||||
- [toml-lang/toml/PR/676](https://github.com/toml-lang/toml/pull/676)
|
||||
- Add new `\e` shorthand for the escape character.
|
||||
|
||||
### Note about heterogeneous arrays
|
||||
## Note about heterogeneous arrays
|
||||
|
||||
Although `toml::parse` allows heterogeneous arrays, constructor of `toml::value`
|
||||
does not.
|
||||
does not. Here the reason is explained.
|
||||
|
||||
```cpp
|
||||
// this won't be compiled
|
||||
@@ -1595,8 +1871,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.
|
||||
Also, you can first initialize a `toml::value` with an array and then
|
||||
`push_back` into it.
|
||||
|
||||
```cpp
|
||||
// OK!
|
||||
@@ -1604,6 +1882,17 @@ toml::value v{
|
||||
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||
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.
|
||||
@@ -1632,15 +1921,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
|
||||
"heterogeneous array as an initializer-list" cannot be implemented.
|
||||
|
||||
Thus, although it is painful, you need to explicitly cast values into
|
||||
`toml::value` when you initialize heterogeneous array in C++ code.
|
||||
Thus, although it is painful, we need to explicitly cast values into
|
||||
`toml::value` when you initialize heterogeneous array in a C++ code.
|
||||
|
||||
```cpp
|
||||
// You need to do this when you want to initialize hetero array.
|
||||
toml::value v{
|
||||
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Breaking Changes from v2
|
||||
@@ -1679,14 +1967,13 @@ Such a big change will not happen in the coming years.
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run test codes, you need to clone toml-lang/toml repository under `build/` directory
|
||||
because some of the test codes read a file in the repository.
|
||||
After cloning this repository, run the following command (thank you @jwillikers
|
||||
for automating test set fetching!).
|
||||
|
||||
```sh
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ git clone https://github.com/toml-lang/toml.git
|
||||
$ cmake ..
|
||||
$ cmake .. -Dtoml11_BUILD_TEST=ON
|
||||
$ make
|
||||
$ make test
|
||||
```
|
||||
@@ -1703,12 +1990,13 @@ I appreciate the help of the contributors who introduced the great feature to th
|
||||
- Intel Compiler support
|
||||
- Quentin Khan (@xaxousis)
|
||||
- Found & Fixed a bug around ODR
|
||||
- Improved error messages for invaild keys to show the location where the parser fails
|
||||
- Improved error messages for invalid keys to show the location where the parser fails
|
||||
- Petr Beneš (@wbenny)
|
||||
- Fixed warnings on MSVC
|
||||
- Ivan Shynkarenka (@chronoxor)
|
||||
- Fixed Visual Studio 2019 warnings
|
||||
- @khoitd1997
|
||||
- Fix compilation error in `<filesystem>` with MinGW
|
||||
- Khoi Dinh Trinh (@khoitd1997)
|
||||
- Fixed warnings while type conversion
|
||||
- @KerstinKeller
|
||||
- Added installation script to CMake
|
||||
@@ -1719,11 +2007,76 @@ I appreciate the help of the contributors who introduced the great feature to th
|
||||
- Suppress warnings in Debug mode
|
||||
- OGAWA Kenichi (@kenichiice)
|
||||
- Suppress warnings on intel compiler
|
||||
- Fix include path in README
|
||||
- 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
|
||||
- Mohammed Alyousef (@MoAlyousef)
|
||||
- Made testing optional in CMake
|
||||
- Alex Merry (@amerry)
|
||||
- Add missing include files
|
||||
- sneakypete81 (@sneakypete81)
|
||||
- Fix typo in error message
|
||||
- Oliver Kahrmann (@founderio)
|
||||
- Fix missing filename in error message if parsed file is empty
|
||||
- Karl Nilsson (@karl-nilsson)
|
||||
- Fix many spelling errors
|
||||
- ohdarling88 (@ohdarling)
|
||||
- Fix a bug in a constructor of serializer
|
||||
- estshorter (@estshorter)
|
||||
- Fix MSVC warning C26478
|
||||
- Philip Top (@phlptp)
|
||||
- Improve checking standard library feature availability check
|
||||
- Louis Marascio (@marascio)
|
||||
- Fix free-nonheap-object warning
|
||||
- Axel Huebl (@ax3l)
|
||||
- Make installation optional if the library is embedded
|
||||
- Ken Matsui (@ken-matsui)
|
||||
- Support user-defined error message prefix
|
||||
- Support dynamic color mode
|
||||
- Giel van Schijndel (@muggenhor)
|
||||
- Remove needless copy in `parse` function
|
||||
- Lukáš Hrázký (@lukash)
|
||||
- Add a `parse(FILE *)` interface and improve file-related error messages
|
||||
- spiderman idog (@spiderman-idog)
|
||||
- Fix typo in README
|
||||
- Jajauma's GitHub (@Jajauma)
|
||||
- Avoid possible lexer truncation warnings
|
||||
- Moritz Klammler (@ctcmkl)
|
||||
- Many patches in (#200) including:
|
||||
- Improve CMake scripts, build process, and test file handling
|
||||
- Detect error when `discard_comments` is accessed
|
||||
- And more.
|
||||
- Chris White (@cxw42)
|
||||
- Fix address-sanitizer error when parsing literal strings having invalid UTF-8 characters
|
||||
- Fix function name in error messages
|
||||
- offa (@offa)
|
||||
- Update checkout action to v3
|
||||
- Update Required CMake version
|
||||
- Cleanup old CI settings
|
||||
- Sergey Vidyuk (@VestniK)
|
||||
- Fix for case when vector iterator is raw pointer
|
||||
- Kfir Gollan (@kfirgollan)
|
||||
- Add installation example with checkinstall and cmake
|
||||
- Martin Tournoij (@arp242)
|
||||
- Escape control characters in keys
|
||||
- @DavidKorczynski
|
||||
- Add fuzzing test based on ClusterFuzzLite
|
||||
- Esonhugh Skyworship (@Esonhugh)
|
||||
- Fix function signature of `strerror_r` on macos
|
||||
|
||||
## Licensing terms
|
||||
|
||||
This product is licensed under the terms of the [MIT License](LICENSE).
|
||||
|
||||
- Copyright (c) 2017-2019 Toru Niina
|
||||
- Copyright (c) 2017-2024 Toru Niina
|
||||
|
||||
All rights reserved.
|
||||
|
||||
@@ -17,10 +17,9 @@ build_script:
|
||||
- cd C:\toml11
|
||||
- mkdir build
|
||||
- cd build
|
||||
- git clone https://github.com/toml-lang/toml.git
|
||||
- file --mime-encoding toml/tests/hard_example_unicode.toml
|
||||
- cmake -G"%generator%" -DBOOST_ROOT=C:/Libraries/boost_1_69_0 ..
|
||||
- cmake -G"%generator%" -DCMAKE_CXX_STANDARD=11 -DBOOST_ROOT=C:/Libraries/boost_1_69_0 -Dtoml11_BUILD_TEST=ON ..
|
||||
- cmake --build . --config "%configuration%"
|
||||
- file --mime-encoding tests/toml/tests/hard_example_unicode.toml
|
||||
|
||||
test_script:
|
||||
- ctest --build-config "%configuration%" --timeout 300 --output-on-failure
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
@PACKAGE_INIT@
|
||||
include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/toml11Targets.cmake")
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
include(ExternalProject)
|
||||
|
||||
set(TOML11_LANGSPEC_GIT_REPOSITORY "https://github.com/toml-lang/toml" CACHE STRING
|
||||
"URL of the TOML language specification repository")
|
||||
|
||||
set(TOML11_LANGSPEC_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/toml" CACHE FILEPATH
|
||||
"directory for the TOML language specification tree")
|
||||
|
||||
if(NOT EXISTS "${TOML11_LANGSPEC_SOURCE_DIR}/toml.abnf")
|
||||
ExternalProject_Add(toml
|
||||
SOURCE_DIR "${TOML11_LANGSPEC_SOURCE_DIR}"
|
||||
GIT_REPOSITORY "${TOML11_LANGSPEC_GIT_REPOSITORY}"
|
||||
GIT_TAG "v0.5.0"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
set(TEST_NAMES
|
||||
test_datetime
|
||||
test_string
|
||||
@@ -27,6 +45,7 @@ set(TEST_NAMES
|
||||
test_get_or
|
||||
test_find
|
||||
test_find_or
|
||||
test_find_or_recursive
|
||||
test_expect
|
||||
test_parse_file
|
||||
test_serialize_file
|
||||
@@ -36,9 +55,105 @@ set(TEST_NAMES
|
||||
test_extended_conversions
|
||||
)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
|
||||
CHECK_CXX_COMPILER_FLAG("-Werror" COMPILER_SUPPORTS_WERROR)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-Wsign-conversion" COMPILER_SUPPORTS_WSIGN_CONVERSION)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wconversion" COMPILER_SUPPORTS_WCONVERSION)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wduplicated-cond" COMPILER_SUPPORTS_WDUPLICATED_COND)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wrange-loop-analysis" COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wundef" COMPILER_SUPPORTS_WUNDEF)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wshadow" COMPILER_SUPPORTS_WSHADOW)
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
# check which standard library implementation is used. If libstdc++ is used,
|
||||
# it will fail to compile. It compiles if libc++ is used.
|
||||
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)
|
||||
|
||||
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
|
||||
|
||||
set(PREVIOUSLY_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}")
|
||||
set(PREVIOUSLY_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}")
|
||||
set(PREVIOUSLY_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
|
||||
list(APPEND CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
if(APPLE)
|
||||
list(APPEND CMAKE_REQUIRED_FLAGS "-std=c++11")
|
||||
endif()
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#define BOOST_TEST_MODULE \"dummy\"
|
||||
#undef BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); }
|
||||
" TOML11_WITH_BOOST_TEST_HEADER)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#define BOOST_TEST_MODULE \"dummy\"
|
||||
#undef BOOST_TEST_DYN_LINK
|
||||
#undef BOOST_TEST_NO_LIB
|
||||
#include <boost/test/unit_test.hpp>
|
||||
BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); }
|
||||
" TOML11_WITH_BOOST_TEST_STATIC)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#define BOOST_TEST_MODULE \"dummy\"
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#undef BOOST_TEST_NO_LIB
|
||||
#include <boost/test/unit_test.hpp>
|
||||
BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); }
|
||||
" TOML11_WITH_BOOST_TEST_DYNAMIC)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES "${PREVIOUSLY_REQUIRED_INCLUDES}")
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${PREVIOUSLY_REQUIRED_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${PREVIOUSLY_REQUIRED_FLAGS}")
|
||||
|
||||
unset(PREVIOUSLY_REQUIRED_INCLUDES)
|
||||
unset(PREVIOUSLY_REQUIRED_LIBRARIES)
|
||||
unset(PREVIOUSLY_REQUIRED_FLAGS)
|
||||
|
||||
if(TOML11_WITH_BOOST_TEST_DYNAMIC)
|
||||
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST -DBOOST_TEST_DYN_LINK)
|
||||
elseif(TOML11_WITH_BOOST_TEST_STATIC)
|
||||
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
|
||||
elseif(TOML11_WITH_BOOST_TEST_HEADER)
|
||||
add_definitions(-DBOOST_TEST_NO_LIB)
|
||||
else()
|
||||
message(FATAL_ERROR "Neither the Boost.Test static or shared library nor the header-only version seem to be usable.")
|
||||
endif()
|
||||
|
||||
if(COMPILER_SUPPORTS_WALL)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
@@ -49,9 +164,39 @@ endif()
|
||||
if(COMPILER_SUPPORTS_WPEDANTIC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
endif()
|
||||
|
||||
option(TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
"use features in toml-lang/toml master while testing" OFF)
|
||||
if(COMPILER_SUPPORTS_WERROR)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
endif()
|
||||
if(COMPILER_SUPPORTS_WSHADOW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
|
||||
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()
|
||||
|
||||
if(TOML11_USE_UNRELEASED_TOML_FEATURES)
|
||||
message(STATUS "adding TOML11_USE_UNRELEASED_TOML_FEATURES flag")
|
||||
@@ -94,29 +239,61 @@ if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4820")
|
||||
# pragma warning(pop): likely mismatch, popping warning state pushed in different file
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd5031")
|
||||
# pragma warning(pop): spectre warnings in tests
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd5045")
|
||||
# pragma warning(pop): spectre warnings in tests
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4265")
|
||||
endif()
|
||||
|
||||
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
|
||||
add_definitions(-DBOOST_TEST_DYN_LINK)
|
||||
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
|
||||
set(TEST_ENVIRON "TOMLDIR=${TOML11_LANGSPEC_SOURCE_DIR}")
|
||||
if(WIN32)
|
||||
# Set the PATH to be able to find Boost DLL
|
||||
STRING(REPLACE ";" "\\;" PATH_STRING "$ENV{PATH}")
|
||||
list(APPEND TEST_ENVIRON "PATH=${PATH_STRING}\;${Boost_LIBRARY_DIRS}")
|
||||
endif()
|
||||
|
||||
foreach(TEST_NAME ${TEST_NAMES})
|
||||
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
|
||||
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
|
||||
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
target_include_directories(${TEST_NAME} SYSTEM PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
target_compile_definitions(${TEST_NAME} PRIVATE "BOOST_TEST_MODULE=\"${TEST_NAME}\"")
|
||||
|
||||
# Set the PATH to be able to find Boost DLL
|
||||
if(WIN32)
|
||||
STRING(REPLACE ";" "\\;" PATH_STRING "$ENV{PATH}")
|
||||
set_tests_properties(${TEST_NAME}
|
||||
PROPERTIES ENVIRONMENT "PATH=${PATH_STRING}\;${Boost_LIBRARY_DIRS}"
|
||||
)
|
||||
# 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})
|
||||
|
||||
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_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${TEST_ENVIRON}")
|
||||
endforeach(TEST_NAME)
|
||||
|
||||
|
||||
# this test is to check it compiles. it will not run
|
||||
add_executable(test_multiple_translation_unit
|
||||
test_multiple_translation_unit_1.cpp
|
||||
test_multiple_translation_unit_2.cpp)
|
||||
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()
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "toml.hpp"
|
||||
#include <toml.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "toml.hpp"
|
||||
#include <iostream>
|
||||
#include <toml.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@@ -22,15 +23,40 @@ int main(int argc, char **argv)
|
||||
|
||||
if(data != serialized)
|
||||
{
|
||||
std::cerr << "============================================================\n";
|
||||
std::cerr << "result (w/o comment) different: " << filename << std::endl;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# serialized\n";
|
||||
std::cerr << serialized;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# data\n";
|
||||
std::cerr << data;
|
||||
return 1;
|
||||
// this is really a ditry hack, but is the easiest way...
|
||||
// TODO: cleanup by adding comparison function to check if a value is NaN or not
|
||||
if(filename.substr(filename.size() - 22, 22) == "float-inf-and-nan.toml" &&
|
||||
std::isnan (toml::find<double>(serialized, "nan")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "nan")) &&
|
||||
std::isnan (toml::find<double>(serialized, "nan_plus")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "nan_plus")) &&
|
||||
std::isnan (toml::find<double>(serialized, "nan_neg")) &&
|
||||
std::signbit (toml::find<double>(serialized, "nan_neg")) &&
|
||||
!std::isnan (toml::find<double>(serialized, "infinity")) &&
|
||||
!std::isfinite(toml::find<double>(serialized, "infinity")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "infinity")) &&
|
||||
!std::isnan (toml::find<double>(serialized, "infinity_plus")) &&
|
||||
!std::isfinite(toml::find<double>(serialized, "infinity_plus")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "infinity_plus")) &&
|
||||
!std::isnan (toml::find<double>(serialized, "infinity_neg")) &&
|
||||
!std::isfinite(toml::find<double>(serialized, "infinity_neg")) &&
|
||||
std::signbit (toml::find<double>(serialized, "infinity_neg")))
|
||||
{
|
||||
// then it is correctly serialized.
|
||||
// Note that, the result of (nan == nan) is false. so `data == serialized` is false.
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "============================================================\n";
|
||||
std::cerr << "result (w/o comment) different: " << filename << std::endl;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# serialized\n";
|
||||
std::cerr << serialized;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# data\n";
|
||||
std::cerr << data;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -42,15 +68,46 @@ int main(int argc, char **argv)
|
||||
const auto serialized = toml::parse<toml::preserve_comments>("tmp.toml");
|
||||
if(data != serialized)
|
||||
{
|
||||
std::cerr << "============================================================\n";
|
||||
std::cerr << "result (w/ comment) different: " << filename << std::endl;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# serialized\n";
|
||||
std::cerr << serialized;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# data\n";
|
||||
std::cerr << data;
|
||||
return 1;
|
||||
// this is really a ditry hack, but is the easiest way...
|
||||
// TODO: cleanup by adding comparison function to check if a value is NaN or not
|
||||
if(filename.substr(filename.size() - 22, 22) == "float-inf-and-nan.toml" &&
|
||||
std::isnan (toml::find<double>(serialized, "nan")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "nan")) &&
|
||||
std::isnan (toml::find<double>(serialized, "nan_plus")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "nan_plus")) &&
|
||||
std::isnan (toml::find<double>(serialized, "nan_neg")) &&
|
||||
std::signbit (toml::find<double>(serialized, "nan_neg")) &&
|
||||
!std::isnan (toml::find<double>(serialized, "infinity")) &&
|
||||
!std::isfinite(toml::find<double>(serialized, "infinity")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "infinity")) &&
|
||||
!std::isnan (toml::find<double>(serialized, "infinity_plus")) &&
|
||||
!std::isfinite(toml::find<double>(serialized, "infinity_plus")) &&
|
||||
!std::signbit (toml::find<double>(serialized, "infinity_plus")) &&
|
||||
!std::isnan (toml::find<double>(serialized, "infinity_neg")) &&
|
||||
!std::isfinite(toml::find<double>(serialized, "infinity_neg")) &&
|
||||
std::signbit (toml::find<double>(serialized, "infinity_neg")) &&
|
||||
toml::find(data, "nan").comments() == toml::find(serialized, "nan").comments() &&
|
||||
toml::find(data, "nan_plus").comments() == toml::find(serialized, "nan_plus").comments() &&
|
||||
toml::find(data, "nan_neg").comments() == toml::find(serialized, "nan_neg").comments() &&
|
||||
toml::find(data, "infinity").comments() == toml::find(serialized, "infinity").comments() &&
|
||||
toml::find(data, "infinity_plus").comments() == toml::find(serialized, "infinity_plus").comments() &&
|
||||
toml::find(data, "infinity_neg").comments() == toml::find(serialized, "infinity_neg").comments() )
|
||||
{
|
||||
// then it is correctly serialized.
|
||||
// Note that, the result of (nan == nan) is false. so `data == serialized` is false.
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "============================================================\n";
|
||||
std::cerr << "result (w/ comment) different: " << filename << std::endl;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# serialized\n";
|
||||
std::cerr << serialized;
|
||||
std::cerr << "------------------------------------------------------------\n";
|
||||
std::cerr << "# data\n";
|
||||
std::cerr << data;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "toml.hpp"
|
||||
#include <iostream>
|
||||
#include <toml.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
struct json_serializer
|
||||
{
|
||||
@@ -16,6 +17,14 @@ struct json_serializer
|
||||
}
|
||||
void operator()(toml::floating v)
|
||||
{
|
||||
if(std::isnan(v) && std::signbit(v))
|
||||
{
|
||||
// toml-test does not allow negative NaN represented in "-nan" because
|
||||
// there are languages that does not distinguish nan and -nan.
|
||||
// But toml11 keeps sign from input. To resolve this difference,
|
||||
// we convert -nan to nan here.
|
||||
v = std::numeric_limits<toml::floating>::quiet_NaN();
|
||||
}
|
||||
std::cout << "{\"type\":\"float\",\"value\":\"" << toml::value(v) << "\"}";
|
||||
return ;
|
||||
}
|
||||
@@ -24,23 +33,24 @@ struct json_serializer
|
||||
// since toml11 automatically convert string to multiline string that is
|
||||
// valid only in TOML, we need to format the string to make it valid in
|
||||
// JSON.
|
||||
std::cout << "{\"type\":\"string\",\"value\":\""
|
||||
<< this->escape_string(v.str) << "\"}";
|
||||
toml::serializer<toml::value> ser(std::numeric_limits<std::size_t>::max());
|
||||
std::cout << "{\"type\":\"string\",\"value\":"
|
||||
<< ser(v.str) << "}";
|
||||
return ;
|
||||
}
|
||||
void operator()(const toml::local_time& v)
|
||||
{
|
||||
std::cout << "{\"type\":\"local_time\",\"value\":\"" << toml::value(v) << "\"}";
|
||||
std::cout << "{\"type\":\"time-local\",\"value\":\"" << toml::value(v) << "\"}";
|
||||
return ;
|
||||
}
|
||||
void operator()(const toml::local_date& v)
|
||||
{
|
||||
std::cout << "{\"type\":\"local_date\",\"value\":\"" << toml::value(v) << "\"}";
|
||||
std::cout << "{\"type\":\"date-local\",\"value\":\"" << toml::value(v) << "\"}";
|
||||
return ;
|
||||
}
|
||||
void operator()(const toml::local_datetime& v)
|
||||
{
|
||||
std::cout << "{\"type\":\"local_datetime\",\"value\":\"" << toml::value(v) << "\"}";
|
||||
std::cout << "{\"type\":\"datetime-local\",\"value\":\"" << toml::value(v) << "\"}";
|
||||
return ;
|
||||
}
|
||||
void operator()(const toml::offset_datetime& v)
|
||||
@@ -64,7 +74,8 @@ struct json_serializer
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "{\"type\":\"array\",\"value\":[";
|
||||
// std::cout << "{\"type\":\"array\",\"value\":[";
|
||||
std::cout << "[";
|
||||
bool is_first = true;
|
||||
for(const auto& elem : v)
|
||||
{
|
||||
@@ -72,7 +83,7 @@ struct json_serializer
|
||||
is_first = false;
|
||||
toml::visit(*this, elem);
|
||||
}
|
||||
std::cout << "]}";
|
||||
std::cout << "]";
|
||||
}
|
||||
return ;
|
||||
}
|
||||
@@ -84,34 +95,20 @@ struct json_serializer
|
||||
{
|
||||
if(!is_first) {std::cout << ", ";}
|
||||
is_first = false;
|
||||
std::cout << toml::format(toml::value(elem.first),
|
||||
std::numeric_limits<std::size_t>::max());
|
||||
std::cout << ':';
|
||||
const auto k = toml::format_key(elem.first);
|
||||
if(k.at(0) == '"')
|
||||
{
|
||||
std::cout << k << ":";
|
||||
}
|
||||
else // bare key
|
||||
{
|
||||
std::cout << '\"' << k << "\":";
|
||||
}
|
||||
toml::visit(*this, elem.second);
|
||||
}
|
||||
std::cout << '}';
|
||||
return ;
|
||||
}
|
||||
|
||||
std::string escape_string(const std::string& s) const
|
||||
{
|
||||
std::string retval;
|
||||
for(const char c : s)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case '\\': {retval += "\\\\"; break;}
|
||||
case '\"': {retval += "\\\""; break;}
|
||||
case '\b': {retval += "\\b"; break;}
|
||||
case '\t': {retval += "\\t"; break;}
|
||||
case '\f': {retval += "\\f"; break;}
|
||||
case '\n': {retval += "\\n"; break;}
|
||||
case '\r': {retval += "\\r"; break;}
|
||||
default : {retval += c; break;}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
#define BOOST_TEST_MODULE "test_comments"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_comment_before)
|
||||
{
|
||||
{
|
||||
const std::string file = u8R"(
|
||||
const std::string file = R"(
|
||||
# comment for a.
|
||||
a = 42
|
||||
# comment for b.
|
||||
@@ -20,16 +14,16 @@ BOOST_AUTO_TEST_CASE(test_comment_before)
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse<toml::preserve_comments>(iss);
|
||||
|
||||
const auto& a = toml::find(v, "a");
|
||||
const auto& b = toml::find(v, "b");
|
||||
const auto a = toml::find(v, "a");
|
||||
const auto b = toml::find(v, "b");
|
||||
|
||||
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().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.
|
||||
# another comment for a.
|
||||
a = 42
|
||||
@@ -41,22 +35,22 @@ BOOST_AUTO_TEST_CASE(test_comment_before)
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse<toml::preserve_comments>(iss);
|
||||
|
||||
const auto& a = toml::find(v, "a");
|
||||
const auto& b = toml::find(v, "b");
|
||||
const auto a = toml::find(v, "a");
|
||||
const auto b = toml::find(v, "b");
|
||||
|
||||
BOOST_TEST(a.comments().size() == 2u);
|
||||
BOOST_TEST(a.comments().front() == u8" comment for a.");
|
||||
BOOST_TEST(a.comments().back() == u8" another comment for a.");
|
||||
BOOST_TEST(a.comments().front() == " comment for a.");
|
||||
BOOST_TEST(a.comments().back() == " another comment for a.");
|
||||
BOOST_TEST(b.comments().size() == 2u);
|
||||
BOOST_TEST(b.comments().front() == u8" comment for b.");
|
||||
BOOST_TEST(b.comments().back() == u8" also comment for b.");
|
||||
BOOST_TEST(b.comments().front() == " comment for b.");
|
||||
BOOST_TEST(b.comments().back() == " also comment for b.");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_comment_inline)
|
||||
{
|
||||
{
|
||||
const std::string file = u8R"(
|
||||
const std::string file = R"(
|
||||
a = 42 # comment for a.
|
||||
b = "baz" # comment for b.
|
||||
)";
|
||||
@@ -64,16 +58,16 @@ BOOST_AUTO_TEST_CASE(test_comment_inline)
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse<toml::preserve_comments>(iss);
|
||||
|
||||
const auto& a = toml::find(v, "a");
|
||||
const auto& b = toml::find(v, "b");
|
||||
const auto a = toml::find(v, "a");
|
||||
const auto b = toml::find(v, "b");
|
||||
|
||||
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().front() == u8" comment for b.");
|
||||
BOOST_TEST(b.comments().front() == " comment for b.");
|
||||
}
|
||||
{
|
||||
const std::string file = u8R"(
|
||||
const std::string file = R"(
|
||||
a = [
|
||||
42,
|
||||
] # comment for a.
|
||||
@@ -85,23 +79,23 @@ BOOST_AUTO_TEST_CASE(test_comment_inline)
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse<toml::preserve_comments>(iss);
|
||||
|
||||
const auto& a = toml::find(v, "a");
|
||||
const auto& b = toml::find(v, "b");
|
||||
const auto& b0 = b.as_array().at(0);
|
||||
const auto a = toml::find(v, "a");
|
||||
const auto b = toml::find(v, "b");
|
||||
const auto b0 = b.as_array().at(0);
|
||||
|
||||
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().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().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)
|
||||
{
|
||||
{
|
||||
const std::string file = u8R"(
|
||||
const std::string file = R"(
|
||||
# comment for a.
|
||||
a = 42 # inline comment for a.
|
||||
# comment for b.
|
||||
@@ -116,31 +110,68 @@ BOOST_AUTO_TEST_CASE(test_comment_both)
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse<toml::preserve_comments>(iss);
|
||||
|
||||
const auto& a = toml::find(v, "a");
|
||||
const auto& b = toml::find(v, "b");
|
||||
const auto& c = toml::find(v, "c");
|
||||
const auto& c0 = c.as_array().at(0);
|
||||
const auto a = toml::find(v, "a");
|
||||
const auto b = toml::find(v, "b");
|
||||
const auto c = toml::find(v, "c");
|
||||
const auto c0 = c.as_array().at(0);
|
||||
|
||||
BOOST_TEST(a.comments().size() == 2u);
|
||||
BOOST_TEST(a.comments().front() == u8" comment for a.");
|
||||
BOOST_TEST(a.comments().back() == u8" inline comment for a.");
|
||||
BOOST_TEST(a.comments().front() == " comment for a.");
|
||||
BOOST_TEST(a.comments().back() == " inline comment for a.");
|
||||
BOOST_TEST(b.comments().size() == 2u);
|
||||
BOOST_TEST(b.comments().front() == u8" comment for b.");
|
||||
BOOST_TEST(b.comments().back() == u8" inline comment for b.");
|
||||
BOOST_TEST(b.comments().front() == " comment for b.");
|
||||
BOOST_TEST(b.comments().back() == " inline comment for b.");
|
||||
|
||||
BOOST_TEST(c.comments().size() == 2u);
|
||||
BOOST_TEST(c.comments().front() == u8" comment for c.");
|
||||
BOOST_TEST(c.comments().back() == u8" another comment for c.");
|
||||
BOOST_TEST(c.comments().front() == " comment for c.");
|
||||
BOOST_TEST(c.comments().back() == " another comment for c.");
|
||||
|
||||
BOOST_TEST(c0.comments().size() == 2u);
|
||||
BOOST_TEST(c0.comments().front() == u8" comment for the first element.");
|
||||
BOOST_TEST(c0.comments().back() == u8" this also.");
|
||||
BOOST_TEST(c0.comments().front() == " comment for the first element.");
|
||||
BOOST_TEST(c0.comments().back() == " this also.");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_comments_on_implicit_values)
|
||||
{
|
||||
{
|
||||
const std::string file = R"(
|
||||
# comment for the first element of array-of-tables.
|
||||
[[array-of-tables]]
|
||||
foo = "bar"
|
||||
)";
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse<toml::preserve_comments>(iss);
|
||||
|
||||
const auto aot = toml::find(v, "array-of-tables");
|
||||
const auto elm = aot.at(0);
|
||||
BOOST_TEST(aot.comments().empty());
|
||||
BOOST_TEST(elm.comments().size() == 1);
|
||||
BOOST_TEST(elm.comments().front() == " comment for the first element of array-of-tables.");
|
||||
}
|
||||
{
|
||||
const std::string file = R"(
|
||||
# comment for the array itself
|
||||
array-of-tables = [
|
||||
# comment for the first element of array-of-tables.
|
||||
{foo = "bar"}
|
||||
]
|
||||
)";
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse<toml::preserve_comments>(iss);
|
||||
|
||||
const auto aot = toml::find(v, "array-of-tables");
|
||||
const auto elm = aot.at(0);
|
||||
BOOST_TEST(aot.comments().size() == 1);
|
||||
BOOST_TEST(aot.comments().front() == " comment for the array itself");
|
||||
BOOST_TEST(elm.comments().size() == 1);
|
||||
BOOST_TEST(elm.comments().front() == " comment for the first element of array-of-tables.");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_discard_comment)
|
||||
{
|
||||
const std::string file = u8R"(
|
||||
const std::string file = R"(
|
||||
# comment for a.
|
||||
a = 42 # inline comment for a.
|
||||
# comment for b.
|
||||
@@ -153,12 +184,12 @@ BOOST_AUTO_TEST_CASE(test_discard_comment)
|
||||
)";
|
||||
|
||||
std::istringstream iss(file);
|
||||
const auto v = toml::parse(iss);
|
||||
const auto v = toml::parse<toml::discard_comments>(iss);
|
||||
|
||||
const auto& a = toml::find(v, "a");
|
||||
const auto& b = toml::find(v, "b");
|
||||
const auto& c = toml::find(v, "c");
|
||||
const auto& c0 = c.as_array().at(0);
|
||||
const auto a = toml::find(v, "a");
|
||||
const auto b = toml::find(v, "b");
|
||||
const auto c = toml::find(v, "c");
|
||||
const auto c0 = c.as_array().at(0);
|
||||
|
||||
BOOST_TEST(a.comments().empty());
|
||||
BOOST_TEST(b.comments().empty());
|
||||
@@ -235,7 +266,7 @@ BOOST_AUTO_TEST_CASE(test_construct_value_with_comments)
|
||||
BOOST_TEST(v.is_string());
|
||||
BOOST_TEST(v.as_string() == "str");
|
||||
}
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
{
|
||||
using namespace std::literals::string_view_literals;
|
||||
const value_type v("str"sv, {"comment1", "comment2"});
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
#define BOOST_TEST_MODULE "test_datetime"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/datetime.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_local_date)
|
||||
{
|
||||
const toml::local_date date(2018, toml::month_t::Jan, 1);
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#define BOOST_TEST_MODULE "test_error_detection"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_detect_empty_key)
|
||||
{
|
||||
@@ -80,13 +76,13 @@ BOOST_AUTO_TEST_CASE(test_detect_conflicting_value)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
|
||||
{
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
BOOST_TEST_MESSAGE("heterogeneous array will be allowed in the next release");
|
||||
#else
|
||||
#ifdef TOML11_DISALLOW_HETEROGENEOUS_ARRAYS
|
||||
std::istringstream stream(std::string(
|
||||
"a = [1, 1.0]\n"
|
||||
));
|
||||
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
||||
#else
|
||||
BOOST_TEST_MESSAGE("After v1.0.0-rc.1, heterogeneous arrays are allowed");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
#define BOOST_TEST_MODULE "test_expect"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <array>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_expect)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
#define BOOST_TEST_MODULE "test_extended_conversions"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
@@ -44,6 +40,16 @@ struct qux
|
||||
int a;
|
||||
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
|
||||
|
||||
namespace toml
|
||||
@@ -60,9 +66,9 @@ struct from<extlib::foo>
|
||||
template<>
|
||||
struct into<extlib::foo>
|
||||
{
|
||||
static toml::table into_toml(const extlib::foo& f)
|
||||
static toml::value into_toml(const extlib::foo& f)
|
||||
{
|
||||
return toml::table{{"a", f.a}, {"b", f.b}};
|
||||
return toml::value{{"a", f.a}, {"b", f.b}};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -122,6 +128,17 @@ struct qux
|
||||
int a;
|
||||
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
|
||||
|
||||
namespace toml
|
||||
@@ -284,6 +301,27 @@ BOOST_AUTO_TEST_CASE(test_conversion_one_way)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_conversion_via_constructor)
|
||||
{
|
||||
{
|
||||
const toml::value v{{"a", 42}, {"b", "foobar"}};
|
||||
|
||||
const auto foobar = toml::get<extlib::foobar>(v);
|
||||
BOOST_TEST(foobar.a == 42);
|
||||
BOOST_TEST(foobar.b == "foobar");
|
||||
}
|
||||
|
||||
{
|
||||
const toml::basic_value<toml::discard_comments, std::map> v{
|
||||
{"a", 42}, {"b", "foobar"}
|
||||
};
|
||||
|
||||
const auto foobar = toml::get<extlib2::foobar>(v);
|
||||
BOOST_TEST(foobar.a == 42);
|
||||
BOOST_TEST(foobar.b == "foobar");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
||||
{
|
||||
{
|
||||
@@ -384,5 +422,206 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
||||
BOOST_TEST(bars.at(2).b == "quux");
|
||||
BOOST_TEST(bars.at(3).b == "foobar");
|
||||
}
|
||||
|
||||
// via constructor
|
||||
{
|
||||
const toml::value v{
|
||||
toml::table{{"a", 42}, {"b", "baz"}},
|
||||
toml::table{{"a", 43}, {"b", "qux"}},
|
||||
toml::table{{"a", 44}, {"b", "quux"}},
|
||||
toml::table{{"a", 45}, {"b", "foobar"}}
|
||||
};
|
||||
|
||||
{
|
||||
const auto foobars = toml::get<std::vector<extlib::foobar>>(v);
|
||||
BOOST_TEST(foobars.size() == 4ul);
|
||||
BOOST_TEST(foobars.at(0).a == 42);
|
||||
BOOST_TEST(foobars.at(1).a == 43);
|
||||
BOOST_TEST(foobars.at(2).a == 44);
|
||||
BOOST_TEST(foobars.at(3).a == 45);
|
||||
|
||||
BOOST_TEST(foobars.at(0).b == "baz");
|
||||
BOOST_TEST(foobars.at(1).b == "qux");
|
||||
BOOST_TEST(foobars.at(2).b == "quux");
|
||||
BOOST_TEST(foobars.at(3).b == "foobar");
|
||||
}
|
||||
{
|
||||
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
|
||||
BOOST_TEST(foobars.size() == 4ul);
|
||||
BOOST_TEST(foobars.at(0).a == 42);
|
||||
BOOST_TEST(foobars.at(1).a == 43);
|
||||
BOOST_TEST(foobars.at(2).a == 44);
|
||||
BOOST_TEST(foobars.at(3).a == 45);
|
||||
|
||||
BOOST_TEST(foobars.at(0).b == "baz");
|
||||
BOOST_TEST(foobars.at(1).b == "qux");
|
||||
BOOST_TEST(foobars.at(2).b == "quux");
|
||||
BOOST_TEST(foobars.at(3).b == "foobar");
|
||||
}
|
||||
}
|
||||
{
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque>
|
||||
v{
|
||||
toml::table{{"a", 42}, {"b", "baz"}},
|
||||
toml::table{{"a", 43}, {"b", "qux"}},
|
||||
toml::table{{"a", 44}, {"b", "quux"}},
|
||||
toml::table{{"a", 45}, {"b", "foobar"}}
|
||||
};
|
||||
|
||||
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
|
||||
BOOST_TEST(foobars.size() == 4ul);
|
||||
BOOST_TEST(foobars.at(0).a == 42);
|
||||
BOOST_TEST(foobars.at(1).a == 43);
|
||||
BOOST_TEST(foobars.at(2).a == 44);
|
||||
BOOST_TEST(foobars.at(3).a == 45);
|
||||
|
||||
BOOST_TEST(foobars.at(0).b == "baz");
|
||||
BOOST_TEST(foobars.at(1).b == "qux");
|
||||
BOOST_TEST(foobars.at(2).b == "quux");
|
||||
BOOST_TEST(foobars.at(3).b == "foobar");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||
|
||||
namespace extlib3
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
int a;
|
||||
std::string b;
|
||||
};
|
||||
struct bar
|
||||
{
|
||||
int a;
|
||||
std::string b;
|
||||
foo f;
|
||||
};
|
||||
|
||||
} // extlib3
|
||||
|
||||
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib3::foo, a, b)
|
||||
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib3::bar, a, b, f)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_conversion_via_macro)
|
||||
{
|
||||
{
|
||||
const toml::value v{{"a", 42}, {"b", "baz"}};
|
||||
|
||||
const auto foo = toml::get<extlib3::foo>(v);
|
||||
BOOST_TEST(foo.a == 42);
|
||||
BOOST_TEST(foo.b == "baz");
|
||||
|
||||
const toml::value v2(foo);
|
||||
BOOST_TEST(v2 == v);
|
||||
}
|
||||
{
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque> v{
|
||||
{"a", 42}, {"b", "baz"}
|
||||
};
|
||||
|
||||
const auto foo = toml::get<extlib3::foo>(v);
|
||||
BOOST_TEST(foo.a == 42);
|
||||
BOOST_TEST(foo.b == "baz");
|
||||
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque> v2(foo);
|
||||
BOOST_TEST(v2 == v);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
{
|
||||
const toml::value v{
|
||||
{"a", 42},
|
||||
{"b", "bar.b"},
|
||||
{"f", toml::table{{"a", 42}, {"b", "foo.b"}}}
|
||||
};
|
||||
|
||||
const auto bar = toml::get<extlib3::bar>(v);
|
||||
BOOST_TEST(bar.a == 42);
|
||||
BOOST_TEST(bar.b == "bar.b");
|
||||
BOOST_TEST(bar.f.a == 42);
|
||||
BOOST_TEST(bar.f.b == "foo.b");
|
||||
|
||||
const toml::value v2(bar);
|
||||
BOOST_TEST(v2 == v);
|
||||
}
|
||||
{
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque> v{
|
||||
{"a", 42},
|
||||
{"b", "bar.b"},
|
||||
{"f", toml::table{{"a", 42}, {"b", "foo.b"}}}
|
||||
};
|
||||
|
||||
const auto bar = toml::get<extlib3::bar>(v);
|
||||
BOOST_TEST(bar.a == 42);
|
||||
BOOST_TEST(bar.b == "bar.b");
|
||||
BOOST_TEST(bar.f.a == 42);
|
||||
BOOST_TEST(bar.f.b == "foo.b");
|
||||
|
||||
const toml::basic_value<toml::discard_comments, std::map, std::deque> v2(bar);
|
||||
BOOST_TEST(v2 == v);
|
||||
}
|
||||
}
|
||||
#endif // TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
#define BOOST_TEST_MODULE "test_find"
|
||||
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include <toml.hpp>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#if __cplusplus >= 201703L
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
#include <tuple>
|
||||
|
||||
using test_value_types = std::tuple<
|
||||
toml::value,
|
||||
toml::basic_value<toml::discard_comments>,
|
||||
toml::basic_value<toml::preserve_comments>,
|
||||
toml::basic_value<toml::discard_comments, std::map, std::deque>,
|
||||
toml::basic_value<toml::preserve_comments, std::map, std::deque>
|
||||
@@ -101,6 +96,78 @@ BOOST_AUTO_TEST_CASE(test_find_throws)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_find_array_throws)
|
||||
{
|
||||
// -----------------------------------------------------------------------
|
||||
// const-reference version
|
||||
{
|
||||
// value is not an array
|
||||
const toml::value v(true);
|
||||
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||
}
|
||||
{
|
||||
// the value corresponding to the key is not the expected type
|
||||
const toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||
}
|
||||
{
|
||||
// the value corresponding to the key is not found
|
||||
const toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
|
||||
}
|
||||
{
|
||||
// the positive control.
|
||||
const toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_TEST(3 == toml::find<int>(v, 2));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// non-const reference version
|
||||
{
|
||||
// value is not an array
|
||||
toml::value v(true);
|
||||
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||
}
|
||||
{
|
||||
// the value corresponding to the key is not the expected type
|
||||
toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
|
||||
}
|
||||
{
|
||||
// the value corresponding to the key is not found
|
||||
toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
|
||||
}
|
||||
{
|
||||
// the positive control.
|
||||
toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_TEST(3 == toml::find<int>(v, 2));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// move version
|
||||
{
|
||||
// value is not an array
|
||||
toml::value v(true);
|
||||
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
|
||||
}
|
||||
{
|
||||
// the value corresponding to the key is not the expected type
|
||||
toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
|
||||
}
|
||||
{
|
||||
// the value corresponding to the key is not found
|
||||
toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_CHECK_THROW(toml::find<toml::integer>(std::move(v), 6), std::out_of_range);
|
||||
}
|
||||
{
|
||||
// the positive control.
|
||||
toml::value v{1, 2, 3, 4, 5};
|
||||
BOOST_TEST(3 == toml::find<int>(std::move(v), 2));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_find_recursive)
|
||||
{
|
||||
// recursively search tables
|
||||
@@ -126,8 +193,76 @@ BOOST_AUTO_TEST_CASE(test_find_recursive)
|
||||
num2 = 42;
|
||||
BOOST_TEST(42 == toml::find<int>(v, a, b, c, d));
|
||||
|
||||
auto num3 = toml::find<toml::integer>(std::move(v), a, b, c, d);
|
||||
auto num3 = toml::find<toml::integer>(v, a, "b", c, "d");
|
||||
BOOST_TEST(42 == num3);
|
||||
|
||||
auto num4 = toml::find<toml::integer>(std::move(v), a, b, c, d);
|
||||
BOOST_TEST(42 == num4);
|
||||
}
|
||||
// recursively search arrays
|
||||
{
|
||||
toml::value v{
|
||||
toml::array{"array", "of", "string"},
|
||||
toml::array{toml::array{1, 2, 3}, toml::array{3.14, 2.71}}
|
||||
};
|
||||
BOOST_TEST("array" == toml::find<std::string>(v, 0, 0));
|
||||
BOOST_TEST("of" == toml::find<std::string>(v, 0, 1));
|
||||
BOOST_TEST("string" == toml::find<std::string>(v, 0, 2));
|
||||
|
||||
BOOST_TEST(1 == toml::find<int>(v, 1, 0, 0));
|
||||
BOOST_TEST(2 == toml::find<int>(v, 1, 0, 1));
|
||||
BOOST_TEST(3 == toml::find<int>(v, 1, 0, 2));
|
||||
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, 1, 1, 0));
|
||||
BOOST_TEST(2.71 == toml::find<double>(v, 1, 1, 1));
|
||||
|
||||
// reference that can be used to modify the content
|
||||
auto& num = toml::find<toml::integer>(v, 1, 0, 2);
|
||||
num = 42;
|
||||
BOOST_TEST( 1 == toml::find<int>(v, 1, 0, 0));
|
||||
BOOST_TEST( 2 == toml::find<int>(v, 1, 0, 1));
|
||||
BOOST_TEST(42 == toml::find<int>(v, 1, 0, 2));
|
||||
|
||||
// move value
|
||||
auto num2 = toml::find<toml::integer>(std::move(v), 1, 0, 2);
|
||||
BOOST_TEST(42 == num2);
|
||||
}
|
||||
// recursively search mixtures
|
||||
{
|
||||
toml::value v = toml::table{{"array", toml::array{
|
||||
toml::array{1, 2, 3},
|
||||
toml::array{
|
||||
toml::table{{"foo", "bar"}, {"baz", "qux"}},
|
||||
toml::table{{"pi", 3.14}, {"e", 2.71}}
|
||||
}}
|
||||
}};
|
||||
|
||||
BOOST_TEST(1 == toml::find<int>(v, "array", 0, 0));
|
||||
BOOST_TEST(2 == toml::find<int>(v, "array", 0, 1));
|
||||
BOOST_TEST(3 == toml::find<int>(v, "array", 0, 2));
|
||||
|
||||
BOOST_TEST("bar" == toml::find<std::string>(v, "array", 1, 0, "foo"));
|
||||
BOOST_TEST("qux" == toml::find<std::string>(v, "array", 1, 0, "baz"));
|
||||
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, "pi"));
|
||||
BOOST_TEST(2.71 == toml::find<double>(v, "array", 1, 1, "e"));
|
||||
|
||||
const std::string ar("array");
|
||||
const auto ar_c = "array";
|
||||
|
||||
const std::string pi("pi");
|
||||
const auto pi_c = "pi";
|
||||
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, "pi"));
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi));
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi_c));
|
||||
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, "pi"));
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi));
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi_c));
|
||||
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi));
|
||||
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi_c));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,10 +444,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_floating_type, value_type, test_value_ty
|
||||
{
|
||||
{
|
||||
value_type v{{"key", 3.14}};
|
||||
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(v, "key"));
|
||||
BOOST_TEST(static_cast<double >(3.14) == toml::find<double >(v, "key"));
|
||||
BOOST_TEST(static_cast<long double>(3.14) == toml::find<long double>(v, "key"));
|
||||
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(std::move(v), "key"));
|
||||
const double ref(3.14);
|
||||
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(v, "key"));
|
||||
BOOST_TEST( ref == toml::find<double >(v, "key"));
|
||||
BOOST_TEST(static_cast<long double>(ref) == toml::find<long double>(v, "key"));
|
||||
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(std::move(v), "key"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +472,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_string_type, value_type, test_value_type
|
||||
BOOST_TEST("foo" == moved);
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
{
|
||||
value_type v{{"key", toml::string("foo", toml::string_t::basic)}};
|
||||
BOOST_TEST("foo" == toml::find<std::string_view>(v, "key"));
|
||||
@@ -373,14 +509,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array, value_type, test_value_types
|
||||
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
||||
|
||||
std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key");
|
||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
toml::find<std::tuple<int, short, unsigned, long>>(v, "key");
|
||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
||||
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||
@@ -420,14 +556,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_move_toml_array, value_type, test_value_
|
||||
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
||||
|
||||
std::array<int, 4> ary = toml::find<std::array<int, 4>>(std::move(v4), "key");
|
||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
toml::find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key");
|
||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
||||
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||
@@ -689,4 +825,3 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_offset_datetime, value_type, test_va
|
||||
BOOST_TEST(tm.tm_sec == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
#define BOOST_TEST_MODULE "test_find_or"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#if __cplusplus >= 201703L
|
||||
#include <unordered_map>
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
using test_value_types = std::tuple<
|
||||
toml::value,
|
||||
toml::basic_value<toml::discard_comments>,
|
||||
toml::basic_value<toml::preserve_comments>,
|
||||
toml::basic_value<toml::discard_comments, std::map, std::deque>,
|
||||
toml::basic_value<toml::preserve_comments, std::map, std::deque>
|
||||
@@ -375,7 +372,8 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
|
||||
toml::value v1{{"key", 42}};
|
||||
toml::value v2{{"key", 3.14}};
|
||||
BOOST_TEST(2.71f == toml::find_or(v1, "key", 2.71f));
|
||||
BOOST_TEST(static_cast<float>(double(3.14)) == toml::find_or(v2, "key", 2.71f));
|
||||
const double ref(3.14);
|
||||
BOOST_TEST(static_cast<float>(ref) == toml::find_or(v2, "key", 2.71f));
|
||||
}
|
||||
{
|
||||
toml::value v1{{"key", 42}};
|
||||
@@ -383,7 +381,8 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
|
||||
const auto moved1 = toml::find_or(std::move(v1), "key", 2.71f);
|
||||
const auto moved2 = toml::find_or(std::move(v2), "key", 2.71f);
|
||||
BOOST_TEST(2.71f == moved1);
|
||||
BOOST_TEST(static_cast<float>(double(3.14)) == moved2);
|
||||
const double ref(3.14);
|
||||
BOOST_TEST(static_cast<float>(ref) == moved2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
393
tests/test_find_or_recursive.cpp
Normal file
393
tests/test_find_or_recursive.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
using test_value_types = std::tuple<
|
||||
toml::basic_value<toml::discard_comments>,
|
||||
toml::basic_value<toml::preserve_comments>,
|
||||
toml::basic_value<toml::discard_comments, std::map, std::deque>,
|
||||
toml::basic_value<toml::preserve_comments, std::map, std::deque>
|
||||
>;
|
||||
|
||||
namespace test
|
||||
{
|
||||
template<typename charT, typename traits, typename T, typename Alloc>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const std::vector<T, Alloc>& v)
|
||||
{
|
||||
os << "[ ";
|
||||
for(const auto& i : v) {os << i << ' ';}
|
||||
os << ']';
|
||||
return os;
|
||||
}
|
||||
template<typename charT, typename traits, typename T, typename Alloc>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const std::deque<T, Alloc>& v)
|
||||
{
|
||||
os << "[ ";
|
||||
for(const auto& i : v) {os << i << ' ';}
|
||||
os << ']';
|
||||
return os;
|
||||
}
|
||||
template<typename charT, typename traits, typename T, typename Alloc>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const std::list<T, Alloc>& v)
|
||||
{
|
||||
os << "[ ";
|
||||
for(const auto& i : v) {os << i << ' ';}
|
||||
os << ']';
|
||||
return os;
|
||||
}
|
||||
template<typename charT, typename traits,
|
||||
typename Key, typename Value, typename Comp, typename Alloc>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os,
|
||||
const std::map<Key, Value, Comp, Alloc>& v)
|
||||
{
|
||||
os << "[ ";
|
||||
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
|
||||
os << ']';
|
||||
return os;
|
||||
}
|
||||
template<typename charT, typename traits,
|
||||
typename Key, typename Value, typename Hash, typename Eq, typename Alloc>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os,
|
||||
const std::unordered_map<Key, Value, Hash, Eq, Alloc>& v)
|
||||
{
|
||||
os << "[ ";
|
||||
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
|
||||
os << ']';
|
||||
return os;
|
||||
}
|
||||
} // test
|
||||
|
||||
#define TOML11_TEST_FIND_OR_EXACT(toml_type, init_expr, opt_expr) \
|
||||
{ \
|
||||
using namespace test; \
|
||||
const toml::toml_type init init_expr ; \
|
||||
const toml::toml_type opt opt_expr ; \
|
||||
const value_type v{{"key1", value_type{{"key2", init}} }};\
|
||||
BOOST_TEST(init != opt); \
|
||||
BOOST_TEST(init == toml::find_or(v, "key1", "key2", opt));\
|
||||
} \
|
||||
/**/
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_exact, value_type, test_value_types)
|
||||
{
|
||||
TOML11_TEST_FIND_OR_EXACT(boolean, ( true), (false))
|
||||
TOML11_TEST_FIND_OR_EXACT(integer, ( 42), ( 54))
|
||||
TOML11_TEST_FIND_OR_EXACT(floating, ( 3.14), ( 2.71))
|
||||
TOML11_TEST_FIND_OR_EXACT(string, ("foo"), ("bar"))
|
||||
TOML11_TEST_FIND_OR_EXACT(local_time, (12, 30, 45), (6, 0, 30))
|
||||
TOML11_TEST_FIND_OR_EXACT(local_date, (2019, toml::month_t::Apr, 1),
|
||||
(1999, toml::month_t::Jan, 2))
|
||||
TOML11_TEST_FIND_OR_EXACT(local_datetime,
|
||||
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
|
||||
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
|
||||
)
|
||||
TOML11_TEST_FIND_OR_EXACT(offset_datetime,
|
||||
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
|
||||
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
|
||||
)
|
||||
{
|
||||
const typename value_type::array_type init{1,2,3,4,5};
|
||||
const typename value_type::array_type opt {6,7,8,9,10};
|
||||
const value_type v{{"key", init}};
|
||||
BOOST_TEST(init != opt);
|
||||
BOOST_TEST(init == toml::find_or(v, "key", opt));
|
||||
}
|
||||
{
|
||||
const typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
|
||||
const typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
|
||||
const value_type v{{"key", init}};
|
||||
BOOST_TEST(init != opt);
|
||||
BOOST_TEST(init == toml::find_or(v, "key", opt));
|
||||
}
|
||||
}
|
||||
#undef TOML11_TEST_FIND_OR_EXACT
|
||||
|
||||
#define TOML11_TEST_FIND_OR_MOVE(toml_type, init_expr, opt_expr) \
|
||||
{ \
|
||||
using namespace test; \
|
||||
const toml::toml_type init init_expr ; \
|
||||
toml::toml_type opt opt_expr ; \
|
||||
value_type v{{"key1", value_type{{"key2", init}} }}; \
|
||||
BOOST_TEST(init != opt); \
|
||||
const auto moved = toml::find_or(std::move(v), "key1", "key2", std::move(opt));\
|
||||
BOOST_TEST(init == moved); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move, value_type, test_value_types)
|
||||
{
|
||||
TOML11_TEST_FIND_OR_MOVE(boolean, ( true), (false))
|
||||
TOML11_TEST_FIND_OR_MOVE(integer, ( 42), ( 54))
|
||||
TOML11_TEST_FIND_OR_MOVE(floating, ( 3.14), ( 2.71))
|
||||
TOML11_TEST_FIND_OR_MOVE(string, ("foo"), ("bar"))
|
||||
TOML11_TEST_FIND_OR_MOVE(local_time, (12, 30, 45), (6, 0, 30))
|
||||
TOML11_TEST_FIND_OR_MOVE(local_date, (2019, toml::month_t::Apr, 1),
|
||||
(1999, toml::month_t::Jan, 2))
|
||||
TOML11_TEST_FIND_OR_MOVE(local_datetime,
|
||||
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
|
||||
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
|
||||
)
|
||||
TOML11_TEST_FIND_OR_MOVE(offset_datetime,
|
||||
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
|
||||
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
|
||||
)
|
||||
{
|
||||
typename value_type::array_type init{1,2,3,4,5};
|
||||
typename value_type::array_type opt {6,7,8,9,10};
|
||||
value_type v{{"key", init}};
|
||||
BOOST_TEST(init != opt);
|
||||
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
|
||||
BOOST_TEST(init == moved);
|
||||
}
|
||||
{
|
||||
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
|
||||
typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
|
||||
value_type v{{"key", init}};
|
||||
BOOST_TEST(init != opt);
|
||||
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
|
||||
BOOST_TEST(init == moved);
|
||||
}
|
||||
}
|
||||
#undef TOML11_TEST_FIND_OR_MOVE
|
||||
|
||||
|
||||
#define TOML11_TEST_FIND_OR_MODIFY(toml_type, init_expr, opt_expr)\
|
||||
{ \
|
||||
using namespace test; \
|
||||
const toml::toml_type init init_expr ; \
|
||||
toml::toml_type opt1 opt_expr ; \
|
||||
toml::toml_type opt2 opt_expr ; \
|
||||
value_type v{{"key1", value_type{{"key2", init}} }}; \
|
||||
BOOST_TEST(init != opt1); \
|
||||
toml::find_or(v, "key1", "key2", opt2) = opt1; \
|
||||
BOOST_TEST(opt1 == toml::find<toml::toml_type>(v, "key1", "key2"));\
|
||||
} \
|
||||
/**/
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_modify, value_type, test_value_types)
|
||||
{
|
||||
TOML11_TEST_FIND_OR_MODIFY(boolean, ( true), (false))
|
||||
TOML11_TEST_FIND_OR_MODIFY(integer, ( 42), ( 54))
|
||||
TOML11_TEST_FIND_OR_MODIFY(floating, ( 3.14), ( 2.71))
|
||||
TOML11_TEST_FIND_OR_MODIFY(string, ("foo"), ("bar"))
|
||||
TOML11_TEST_FIND_OR_MODIFY(local_time, (12, 30, 45), (6, 0, 30))
|
||||
TOML11_TEST_FIND_OR_MODIFY(local_date, (2019, toml::month_t::Apr, 1),
|
||||
(1999, toml::month_t::Jan, 2))
|
||||
TOML11_TEST_FIND_OR_MODIFY(local_datetime,
|
||||
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
|
||||
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
|
||||
)
|
||||
TOML11_TEST_FIND_OR_MODIFY(offset_datetime,
|
||||
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
|
||||
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
|
||||
)
|
||||
{
|
||||
typename value_type::array_type init{1,2,3,4,5};
|
||||
typename value_type::array_type opt1{6,7,8,9,10};
|
||||
typename value_type::array_type opt2{6,7,8,9,10};
|
||||
BOOST_TEST(init != opt1);
|
||||
value_type v{{"key", init}};
|
||||
toml::find_or(v, "key", opt2) = opt1;
|
||||
BOOST_TEST(opt1 == toml::find<typename value_type::array_type>(v, "key"));
|
||||
}
|
||||
{
|
||||
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
|
||||
typename value_type::table_type opt1{{"key1", 54}, {"key2", "bar"}};
|
||||
typename value_type::table_type opt2{{"key1", 54}, {"key2", "bar"}};
|
||||
value_type v{{"key", init}};
|
||||
BOOST_TEST(init != opt1);
|
||||
toml::find_or(v, "key", opt2) = opt1;
|
||||
BOOST_TEST(opt1 == toml::find<typename value_type::table_type>(v, "key"));
|
||||
}
|
||||
}
|
||||
#undef TOML11_TEST_FIND_OR_MODIFY
|
||||
|
||||
#define TOML11_TEST_FIND_OR_FALLBACK(init_type, opt_type) \
|
||||
{ \
|
||||
using namespace test; \
|
||||
value_type v1{{"key1", value_type{{"key3", "foo"}}}}; \
|
||||
BOOST_TEST(opt_type == toml::find_or(v1, "key1", "key2", opt_type));\
|
||||
value_type v2{{"key1", "foo"}}; \
|
||||
BOOST_TEST(opt_type == toml::find_or(v2, "key1", "key3", opt_type));\
|
||||
} \
|
||||
/**/
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_fallback, value_type, test_value_types)
|
||||
{
|
||||
const toml::boolean boolean (true);
|
||||
const toml::integer integer (42);
|
||||
const toml::floating floating (3.14);
|
||||
const toml::string string ("foo");
|
||||
const toml::local_time local_time (12, 30, 45);
|
||||
const toml::local_date local_date (2019, toml::month_t::Apr, 1);
|
||||
const toml::local_datetime local_datetime (
|
||||
toml::local_date(2019, toml::month_t::Apr, 1),
|
||||
toml::local_time(12, 30, 45));
|
||||
const toml::offset_datetime offset_datetime(
|
||||
toml::local_date(2019, toml::month_t::Apr, 1),
|
||||
toml::local_time(12, 30, 45), toml::time_offset( 9, 0));
|
||||
|
||||
using array_type = typename value_type::array_type;
|
||||
using table_type = typename value_type::table_type;
|
||||
const array_type array{1, 2, 3, 4, 5};
|
||||
const table_type table{{"key1", 42}, {"key2", "foo"}};
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(boolean, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(integer, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(floating, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(string, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_time, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_date, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, array );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(array, table );
|
||||
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, boolean );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, integer );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, floating );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, string );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, local_time );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, local_date );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, local_datetime );
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, offset_datetime);
|
||||
TOML11_TEST_FIND_OR_FALLBACK(table, array );
|
||||
}
|
||||
#undef TOML11_TEST_FIND_OR_FALLBACK
|
||||
|
||||
struct move_only_type
|
||||
{
|
||||
explicit move_only_type(const std::string& n): name_(n) {}
|
||||
|
||||
void from_toml(const toml::value& v)
|
||||
{
|
||||
this->name_ = toml::find<std::string>(v, "name");
|
||||
return;
|
||||
}
|
||||
|
||||
move_only_type(): name_("default"){}
|
||||
~move_only_type() = default;
|
||||
move_only_type(move_only_type&&) = default;
|
||||
move_only_type& operator=(move_only_type&&) = default;
|
||||
move_only_type(const move_only_type&) = delete;
|
||||
move_only_type& operator=(const move_only_type&) = delete;
|
||||
|
||||
bool operator==(const move_only_type& other) const noexcept {return this->name_ == other.name_;}
|
||||
bool operator!=(const move_only_type& other) const noexcept {return this->name_ != other.name_;}
|
||||
bool operator< (const move_only_type& other) const noexcept {return this->name_ < other.name_;}
|
||||
bool operator<=(const move_only_type& other) const noexcept {return this->name_ <= other.name_;}
|
||||
bool operator> (const move_only_type& other) const noexcept {return this->name_ > other.name_;}
|
||||
bool operator>=(const move_only_type& other) const noexcept {return this->name_ >= other.name_;}
|
||||
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const move_only_type& mot)
|
||||
{
|
||||
os << mot.name_;
|
||||
return os;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move_only, value_type, test_value_types)
|
||||
{
|
||||
const move_only_type ref("reference");
|
||||
move_only_type opt("optional");
|
||||
{
|
||||
const value_type v{{"key1", value_type{{"key2", value_type{{"name", "reference"}} }} }};
|
||||
BOOST_TEST(ref == toml::find_or(v, "key1", "key2", std::move(opt)));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
#define BOOST_TEST_MODULE "test_format_error"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// to check it successfully compiles. it does not check the formatted string.
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
#define BOOST_TEST_MODULE "test_get"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#if __cplusplus >= 201703L
|
||||
#include <unordered_map>
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
using test_value_types = std::tuple<
|
||||
toml::value,
|
||||
toml::basic_value<toml::discard_comments>,
|
||||
toml::basic_value<toml::preserve_comments>,
|
||||
toml::basic_value<toml::discard_comments, std::map, std::deque>,
|
||||
toml::basic_value<toml::preserve_comments, std::map, std::deque>
|
||||
@@ -195,11 +192,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_floating_type, value_type, test_value_typ
|
||||
{
|
||||
{
|
||||
value_type v(3.14);
|
||||
BOOST_TEST(static_cast<float >(3.14) == toml::get<float >(v));
|
||||
BOOST_TEST(static_cast<double >(3.14) == toml::get<double >(v));
|
||||
BOOST_TEST(static_cast<long double>(3.14) == toml::get<long double>(v));
|
||||
|
||||
BOOST_TEST(3.14f == toml::get<float>(std::move(v)));
|
||||
const double ref(3.14);
|
||||
BOOST_TEST(static_cast<float >(ref) == toml::get<float >(v));
|
||||
BOOST_TEST( ref == toml::get<double >(v));
|
||||
BOOST_TEST(static_cast<long double>(ref) == toml::get<long double>(v));
|
||||
BOOST_TEST(static_cast<float >(ref) == toml::get<float>(std::move(v)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +221,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_string_type, value_type, test_value_types
|
||||
BOOST_TEST("foobar" == x);
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
{
|
||||
value_type v("foo", toml::string_t::basic);
|
||||
BOOST_TEST("foo" == toml::get<std::string_view>(v));
|
||||
@@ -262,14 +259,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
|
||||
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
|
||||
|
||||
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
|
||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
toml::get<std::tuple<int, short, unsigned, long>>(v);
|
||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
||||
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||
@@ -308,16 +305,16 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
|
||||
{
|
||||
value_type v{42, 54, 69, 72};
|
||||
std::array<int, 4> ary = toml::get<std::array<int, 4>>(std::move(v));
|
||||
BOOST_TEST(static_cast<int>(42) == ary.at(0));
|
||||
BOOST_TEST(static_cast<int>(54) == ary.at(1));
|
||||
BOOST_TEST(static_cast<int>(69) == ary.at(2));
|
||||
BOOST_TEST(static_cast<int>(72) == ary.at(3));
|
||||
BOOST_TEST(42 == ary.at(0));
|
||||
BOOST_TEST(54 == ary.at(1));
|
||||
BOOST_TEST(69 == ary.at(2));
|
||||
BOOST_TEST(72 == ary.at(3));
|
||||
}
|
||||
{
|
||||
value_type v{42, 54, 69, 72};
|
||||
std::tuple<int, short, unsigned, long> tpl =
|
||||
toml::get<std::tuple<int, short, unsigned, long>>(std::move(v));
|
||||
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
|
||||
BOOST_TEST( 42 == std::get<0>(tpl));
|
||||
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
|
||||
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
|
||||
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
|
||||
@@ -506,4 +503,3 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_offset_datetime, value_type, test_va
|
||||
BOOST_TEST(tm.tm_sec == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
#define BOOST_TEST_MODULE "test_get_or"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#if __cplusplus >= 201703L
|
||||
#include <unordered_map>
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
using test_value_types = std::tuple<
|
||||
toml::value,
|
||||
toml::basic_value<toml::discard_comments>,
|
||||
toml::basic_value<toml::preserve_comments>,
|
||||
toml::basic_value<toml::discard_comments, std::map, std::deque>,
|
||||
toml::basic_value<toml::preserve_comments, std::map, std::deque>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
do { \
|
||||
const std::string token (tkn); \
|
||||
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); \
|
||||
BOOST_TEST(result.is_ok()); \
|
||||
if(result.is_ok()){ \
|
||||
@@ -28,7 +28,7 @@ do { \
|
||||
#define TOML11_TEST_LEX_REJECT(lxr, tkn) \
|
||||
do { \
|
||||
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); \
|
||||
BOOST_TEST(result.is_err()); \
|
||||
const bool loc_same = (loc.begin() == loc.iter()); \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "test_lex_boolean"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <toml/lexer.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_lex_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "test_lex_datetime"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <toml/lexer.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_lex_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#define BOOST_TEST_MODULE "test_lex_floating"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <toml/lexer.hpp>
|
||||
#include <limits>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_lex_aux.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
using namespace toml;
|
||||
using namespace detail;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "test_lex_integer"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <toml/lexer.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_lex_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "lex_key_comment_test"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <toml/lexer.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_lex_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -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, "\"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\"",
|
||||
"\"\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, "'quoted \"value\"'", "'quoted \"value\"'");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "test_lex_string"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <toml/lexer.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_lex_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -31,15 +31,9 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
|
||||
"\"192.168.1.1\"",
|
||||
"\"192.168.1.1\"");
|
||||
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"",
|
||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"");
|
||||
#else
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
u8"\"中国\"",
|
||||
u8"\"中国\"");
|
||||
#endif
|
||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"", // UTF-8 string (means "China" in
|
||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\""); // Chinese characters)
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"You'll hate me after this - #\"",
|
||||
@@ -57,6 +51,22 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||
@@ -83,4 +93,16 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"''''That's still pointless', she said.'''",
|
||||
"''''That's still pointless', she said.'''");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''");
|
||||
|
||||
TOML11_TEST_LEX_ACCEPT(lex_string,
|
||||
"''''This,' she said, 'is just a pointless statement.''''",
|
||||
"''''This,' she said, 'is just a pointless statement.''''");
|
||||
}
|
||||
|
||||
@@ -1,17 +1,177 @@
|
||||
#define BOOST_TEST_MODULE "test_literals"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_file_as_literal)
|
||||
{
|
||||
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 v = u8R"(
|
||||
@@ -59,7 +219,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;
|
||||
|
||||
@@ -98,15 +258,18 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
||||
const toml::value v2 = u8R"('foo')"_toml;
|
||||
const toml::value v3 = u8R"("""foo""")"_toml;
|
||||
const toml::value v4 = u8R"('''foo''')"_toml;
|
||||
const toml::value v5 = u8R"("ひらがな")"_toml;
|
||||
|
||||
BOOST_TEST(v1.is_string());
|
||||
BOOST_TEST(v2.is_string());
|
||||
BOOST_TEST(v3.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>(v2) == "foo");
|
||||
BOOST_TEST(toml::get<std::string>(v3) == "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 +327,7 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
|
||||
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(toml::get<toml::offset_datetime>(v1) ==
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "parse_array<toml::value>_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -13,30 +8,30 @@ using namespace detail;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_oneline_array)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[]", array());
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[]", array());
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
|
||||
a[3] = toml::value(1); a[4] = toml::value(5);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,1,4,1,5]", a);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[3,1,4,1,5]", a);
|
||||
}
|
||||
{
|
||||
array a(3);
|
||||
a[0] = toml::value("foo"); a[1] = toml::value("bar");
|
||||
a[2] = toml::value("baz");
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\"]", a);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\"]", a);
|
||||
}
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
|
||||
a[3] = toml::value(1); a[4] = toml::value(5);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,1,4,1,5,]", a);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[3,1,4,1,5,]", a);
|
||||
}
|
||||
{
|
||||
array a(3);
|
||||
a[0] = toml::value("foo"); a[1] = toml::value("bar");
|
||||
a[2] = toml::value("baz");
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\",]", a);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\",]", a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,62 +66,153 @@ BOOST_AUTO_TEST_CASE(test_oneline_array_value)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_multiline_array)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\n#comment\n]", array());
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value< discard_comments>>, "[\n#comment\n]", typename basic_value< discard_comments>::array_type());
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[\n#comment\n]", typename basic_value<preserve_comments>::array_type());
|
||||
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
|
||||
a[3] = toml::value(1); a[4] = toml::value(5);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,\n1,\n4,\n1,\n5]", a);
|
||||
typename basic_value<discard_comments>::array_type a(5);
|
||||
a[0] = basic_value<discard_comments>(3);
|
||||
a[1] = basic_value<discard_comments>(1);
|
||||
a[2] = basic_value<discard_comments>(4);
|
||||
a[3] = basic_value<discard_comments>(1);
|
||||
a[4] = basic_value<discard_comments>(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[3,\n1,\n4,\n1,\n5]", a);
|
||||
}
|
||||
{
|
||||
array a(3);
|
||||
a[0] = toml::value("foo"); a[1] = toml::value("bar");
|
||||
a[2] = toml::value("baz");
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
|
||||
typename basic_value<preserve_comments>::array_type a(5);
|
||||
a[0] = basic_value<preserve_comments>(3);
|
||||
a[1] = basic_value<preserve_comments>(1);
|
||||
a[2] = basic_value<preserve_comments>(4);
|
||||
a[3] = basic_value<preserve_comments>(1);
|
||||
a[4] = basic_value<preserve_comments>(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[3,\n1,\n4,\n1,\n5]", a);
|
||||
}
|
||||
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
|
||||
a[3] = toml::value(1); a[4] = toml::value(5);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5]", a);
|
||||
typename basic_value<discard_comments>::array_type a(5);
|
||||
a[0] = basic_value<discard_comments>(3);
|
||||
a[1] = basic_value<discard_comments>(1);
|
||||
a[2] = basic_value<discard_comments>(4);
|
||||
a[3] = basic_value<discard_comments>(1);
|
||||
a[4] = basic_value<discard_comments>(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a);
|
||||
}
|
||||
{
|
||||
array a(3);
|
||||
a[0] = toml::value("foo"); a[1] = toml::value("b#r");
|
||||
a[2] = toml::value("b#z");
|
||||
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
|
||||
typename basic_value<preserve_comments>::array_type a(5);
|
||||
a[0] = basic_value<preserve_comments>(3, {"comment"});
|
||||
a[1] = basic_value<preserve_comments>(1, {"comment"});
|
||||
a[2] = basic_value<preserve_comments>(4, {"comment"});
|
||||
a[3] = basic_value<preserve_comments>(1, {"comment"});
|
||||
a[4] = basic_value<preserve_comments>(5, {"comment"});
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
typename basic_value<discard_comments>::array_type a(3);
|
||||
a[0] = basic_value<discard_comments>("foo");
|
||||
a[1] = basic_value<discard_comments>("bar");
|
||||
a[2] = basic_value<discard_comments>("baz");
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
|
||||
}
|
||||
{
|
||||
typename basic_value<preserve_comments>::array_type a(3);
|
||||
a[0] = basic_value<preserve_comments>("foo");
|
||||
a[1] = basic_value<preserve_comments>("bar");
|
||||
a[2] = basic_value<preserve_comments>("baz");
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
|
||||
}
|
||||
|
||||
{
|
||||
typename basic_value<discard_comments>::array_type a(3);
|
||||
a[0] = basic_value<discard_comments>("foo");
|
||||
a[1] = basic_value<discard_comments>("b#r");
|
||||
a[2] = basic_value<discard_comments>("b#z");
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
|
||||
}
|
||||
{
|
||||
typename basic_value<preserve_comments>::array_type a(3);
|
||||
a[0] = basic_value<preserve_comments>("foo", {"comment"});
|
||||
a[1] = basic_value<preserve_comments>("b#r", {"comment"});
|
||||
a[2] = basic_value<preserve_comments>("b#z", {"comment"});
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_multiline_array_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\n#comment\n]", toml::value(array()));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value< discard_comments>>, "[\n#comment\n]", basic_value< discard_comments>(typename basic_value< discard_comments>::array_type()));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\n#comment\n]", basic_value<preserve_comments>(typename basic_value<preserve_comments>::array_type()));
|
||||
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
|
||||
a[3] = toml::value(1); a[4] = toml::value(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[3,\n1,\n4,\n1,\n5]", toml::value(a));
|
||||
typename basic_value<discard_comments>::array_type a(5);
|
||||
a[0] = basic_value<discard_comments>(3);
|
||||
a[1] = basic_value<discard_comments>(1);
|
||||
a[2] = basic_value<discard_comments>(4);
|
||||
a[3] = basic_value<discard_comments>(1);
|
||||
a[4] = basic_value<discard_comments>(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[3,\n1,\n4,\n1,\n5]", basic_value<discard_comments>(a));
|
||||
}
|
||||
{
|
||||
array a(3);
|
||||
a[0] = toml::value("foo"); a[1] = toml::value("bar");
|
||||
a[2] = toml::value("baz");
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n\"bar\",\n\"baz\"]", toml::value(a));
|
||||
typename basic_value<preserve_comments>::array_type a(5);
|
||||
a[0] = basic_value<preserve_comments>(3);
|
||||
a[1] = basic_value<preserve_comments>(1);
|
||||
a[2] = basic_value<preserve_comments>(4);
|
||||
a[3] = basic_value<preserve_comments>(1);
|
||||
a[4] = basic_value<preserve_comments>(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[3,\n1,\n4,\n1,\n5]", basic_value<preserve_comments>(a));
|
||||
}
|
||||
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
|
||||
a[3] = toml::value(1); a[4] = toml::value(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5]", toml::value(a));
|
||||
typename basic_value<discard_comments>::array_type a(5);
|
||||
a[0] = basic_value<discard_comments>(3);
|
||||
a[1] = basic_value<discard_comments>(1);
|
||||
a[2] = basic_value<discard_comments>(4);
|
||||
a[3] = basic_value<discard_comments>(1);
|
||||
a[4] = basic_value<discard_comments>(5);
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value<discard_comments>(a));
|
||||
}
|
||||
{
|
||||
array a(3);
|
||||
a[0] = toml::value("foo"); a[1] = toml::value("b#r");
|
||||
a[2] = toml::value("b#z");
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", toml::value(a));
|
||||
typename basic_value<preserve_comments>::array_type a(5);
|
||||
a[0] = basic_value<preserve_comments>(3, {"comment"});
|
||||
a[1] = basic_value<preserve_comments>(1, {"comment"});
|
||||
a[2] = basic_value<preserve_comments>(4, {"comment"});
|
||||
a[3] = basic_value<preserve_comments>(1, {"comment"});
|
||||
a[4] = basic_value<preserve_comments>(5, {"comment"});
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value<preserve_comments>(a));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
typename basic_value<discard_comments>::array_type a(3);
|
||||
a[0] = basic_value<discard_comments>("foo");
|
||||
a[1] = basic_value<discard_comments>("bar");
|
||||
a[2] = basic_value<discard_comments>("baz");
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value<discard_comments>(a));
|
||||
}
|
||||
{
|
||||
typename basic_value<preserve_comments>::array_type a(3);
|
||||
a[0] = basic_value<preserve_comments>("foo");
|
||||
a[1] = basic_value<preserve_comments>("bar");
|
||||
a[2] = basic_value<preserve_comments>("baz");
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value<preserve_comments>(a));
|
||||
}
|
||||
|
||||
{
|
||||
typename basic_value<discard_comments>::array_type a(3);
|
||||
a[0] = basic_value<discard_comments>("foo");
|
||||
a[1] = basic_value<discard_comments>("b#r");
|
||||
a[2] = basic_value<discard_comments>("b#z");
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value<discard_comments>(a));
|
||||
}
|
||||
{
|
||||
typename basic_value<preserve_comments>::array_type a(3);
|
||||
a[0] = basic_value<preserve_comments>("foo", {"comment"});
|
||||
a[1] = basic_value<preserve_comments>("b#r", {"comment"});
|
||||
a[2] = basic_value<preserve_comments>("b#z", {"comment"});
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value<preserve_comments>(a));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_heterogeneous_array)
|
||||
@@ -172,3 +258,31 @@ BOOST_AUTO_TEST_CASE(test_heterogeneous_array)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_comments_after_comma)
|
||||
{
|
||||
{
|
||||
typename basic_value<discard_comments>::array_type a(3);
|
||||
a[0] = basic_value<discard_comments>("foo");
|
||||
a[1] = basic_value<discard_comments>("bar");
|
||||
a[2] = basic_value<discard_comments>("baz");
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>,
|
||||
"[ \"foo\" # comment\n"
|
||||
", \"bar\" # comment\n"
|
||||
", \"baz\" # comment\n"
|
||||
"]", basic_value<discard_comments>(a));
|
||||
}
|
||||
|
||||
{
|
||||
typename basic_value<preserve_comments>::array_type a(3);
|
||||
a[0] = basic_value<preserve_comments>("foo", {" comment"});
|
||||
a[1] = basic_value<preserve_comments>("bar", {" comment"});
|
||||
a[2] = basic_value<preserve_comments>("baz", {" comment"});
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>,
|
||||
"[ \"foo\" # comment\n"
|
||||
", \"bar\" # comment\n"
|
||||
", \"baz\" # comment\n"
|
||||
"]", basic_value<preserve_comments>(a));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#define TOML11_TEST_PARSE_EQUAL(psr, tkn, expct) \
|
||||
do { \
|
||||
const std::string token(tkn); \
|
||||
toml::detail::location<std::string> loc("test", token); \
|
||||
toml::detail::location loc("test", token); \
|
||||
const auto result = psr(loc); \
|
||||
BOOST_TEST(result.is_ok()); \
|
||||
if(result.is_ok()){ \
|
||||
@@ -20,11 +20,27 @@ do { \
|
||||
} while(false); \
|
||||
/**/
|
||||
|
||||
#define TOML11_TEST_PARSE_EQUAL_VAT(psr, tkn, expct) \
|
||||
do { \
|
||||
const std::string token(tkn); \
|
||||
toml::detail::location loc("test", token); \
|
||||
const auto result = psr(loc, 0); \
|
||||
BOOST_TEST(result.is_ok()); \
|
||||
if(result.is_ok()){ \
|
||||
BOOST_TEST(result.unwrap().first == expct); \
|
||||
} else { \
|
||||
std::cerr << "parser " << #psr << " failed with input `"; \
|
||||
std::cerr << token << "`.\n"; \
|
||||
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
|
||||
} \
|
||||
} while(false); \
|
||||
/**/
|
||||
|
||||
#define TOML11_TEST_PARSE_EQUAL_VALUE(psr, tkn, expct) \
|
||||
do { \
|
||||
const std::string token(tkn); \
|
||||
toml::detail::location<std::string> loc("test", token); \
|
||||
const auto result = psr(loc); \
|
||||
toml::detail::location loc("test", token); \
|
||||
const auto result = psr(loc, 0); \
|
||||
BOOST_TEST(result.is_ok()); \
|
||||
if(result.is_ok()){ \
|
||||
BOOST_TEST(result.unwrap() == expct); \
|
||||
@@ -35,3 +51,4 @@ do { \
|
||||
} \
|
||||
} while(false); \
|
||||
/**/
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "test_parse_boolean"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "parse_datetime_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -17,6 +12,11 @@ BOOST_AUTO_TEST_CASE(test_time)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.99", toml::local_time(7, 32, 0, 990, 0));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999", toml::local_time(7, 32, 0, 999, 0));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999999", toml::local_time(7, 32, 0, 999, 999));
|
||||
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "00:00:00.000000", toml::local_time( 0, 0, 0, 0, 0));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:59.999999", toml::local_time(23, 59, 59, 999, 999));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:60.999999", toml::local_time(23, 59, 60, 999, 999)); // leap second
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_time_value)
|
||||
@@ -25,17 +25,125 @@ BOOST_AUTO_TEST_CASE(test_time_value)
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.99", toml::value(toml::local_time(7, 32, 0, 990, 0)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999", toml::value(toml::local_time(7, 32, 0, 999, 0)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999999", toml::value(toml::local_time(7, 32, 0, 999, 999)));
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "00:00:00.000000", toml::value(toml::local_time( 0, 0, 0, 0, 0)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "23:59:59.999999", toml::value(toml::local_time(23, 59, 59, 999, 999)));
|
||||
|
||||
std::istringstream stream1(std::string("invalid-datetime = 24:00:00"));
|
||||
std::istringstream stream2(std::string("invalid-datetime = 00:60:00"));
|
||||
std::istringstream stream3(std::string("invalid-datetime = 00:00:61"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream3), toml::syntax_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_date)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27",
|
||||
toml::local_date(1979, toml::month_t::May, 27));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27", toml::local_date(1979, toml::month_t::May, 27));
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-01", toml::local_date(2000, toml::month_t::Jan, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-31", toml::local_date(2000, toml::month_t::Jan, 31));
|
||||
std::istringstream stream1_1(std::string("invalid-datetime = 2000-01-00"));
|
||||
std::istringstream stream1_2(std::string("invalid-datetime = 2000-01-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream1_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream1_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-01", toml::local_date(2000, toml::month_t::Feb, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-29", toml::local_date(2000, toml::month_t::Feb, 29));
|
||||
std::istringstream stream2_1(std::string("invalid-datetime = 2000-02-00"));
|
||||
std::istringstream stream2_2(std::string("invalid-datetime = 2000-02-30"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2001-02-28", toml::local_date(2001, toml::month_t::Feb, 28));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2004-02-29", toml::local_date(2004, toml::month_t::Feb, 29));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2100-02-28", toml::local_date(2100, toml::month_t::Feb, 28));
|
||||
std::istringstream stream2_3(std::string("invalid-datetime = 2001-02-29"));
|
||||
std::istringstream stream2_4(std::string("invalid-datetime = 2004-02-30"));
|
||||
std::istringstream stream2_5(std::string("invalid-datetime = 2100-02-29"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_3), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_4), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2_5), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-01", toml::local_date(2000, toml::month_t::Mar, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-31", toml::local_date(2000, toml::month_t::Mar, 31));
|
||||
std::istringstream stream3_1(std::string("invalid-datetime = 2000-03-00"));
|
||||
std::istringstream stream3_2(std::string("invalid-datetime = 2000-03-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream3_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream3_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-01", toml::local_date(2000, toml::month_t::Apr, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-30", toml::local_date(2000, toml::month_t::Apr, 30));
|
||||
std::istringstream stream4_1(std::string("invalid-datetime = 2000-04-00"));
|
||||
std::istringstream stream4_2(std::string("invalid-datetime = 2000-04-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream4_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream4_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-01", toml::local_date(2000, toml::month_t::May, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-31", toml::local_date(2000, toml::month_t::May, 31));
|
||||
std::istringstream stream5_1(std::string("invalid-datetime = 2000-05-00"));
|
||||
std::istringstream stream5_2(std::string("invalid-datetime = 2000-05-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream5_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream5_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-01", toml::local_date(2000, toml::month_t::Jun, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-30", toml::local_date(2000, toml::month_t::Jun, 30));
|
||||
std::istringstream stream6_1(std::string("invalid-datetime = 2000-06-00"));
|
||||
std::istringstream stream6_2(std::string("invalid-datetime = 2000-06-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream6_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream6_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-01", toml::local_date(2000, toml::month_t::Jul, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-31", toml::local_date(2000, toml::month_t::Jul, 31));
|
||||
std::istringstream stream7_1(std::string("invalid-datetime = 2000-07-00"));
|
||||
std::istringstream stream7_2(std::string("invalid-datetime = 2000-07-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream7_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream7_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-01", toml::local_date(2000, toml::month_t::Aug, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-31", toml::local_date(2000, toml::month_t::Aug, 31));
|
||||
std::istringstream stream8_1(std::string("invalid-datetime = 2000-08-00"));
|
||||
std::istringstream stream8_2(std::string("invalid-datetime = 2000-08-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream8_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream8_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-01", toml::local_date(2000, toml::month_t::Sep, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-30", toml::local_date(2000, toml::month_t::Sep, 30));
|
||||
std::istringstream stream9_1(std::string("invalid-datetime = 2000-09-00"));
|
||||
std::istringstream stream9_2(std::string("invalid-datetime = 2000-09-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream9_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream9_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-01", toml::local_date(2000, toml::month_t::Oct, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-31", toml::local_date(2000, toml::month_t::Oct, 31));
|
||||
std::istringstream stream10_1(std::string("invalid-datetime = 2000-10-00"));
|
||||
std::istringstream stream10_2(std::string("invalid-datetime = 2000-10-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream10_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream10_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-01", toml::local_date(2000, toml::month_t::Nov, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-30", toml::local_date(2000, toml::month_t::Nov, 30));
|
||||
std::istringstream stream11_1(std::string("invalid-datetime = 2000-11-00"));
|
||||
std::istringstream stream11_2(std::string("invalid-datetime = 2000-11-31"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream11_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream11_2), toml::syntax_error);
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-01", toml::local_date(2000, toml::month_t::Dec, 1));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-31", toml::local_date(2000, toml::month_t::Dec, 31));
|
||||
std::istringstream stream12_1(std::string("invalid-datetime = 2000-12-00"));
|
||||
std::istringstream stream12_2(std::string("invalid-datetime = 2000-12-32"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream12_1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream12_2), toml::syntax_error);
|
||||
|
||||
std::istringstream stream13_1(std::string("invalid-datetime = 2000-13-01"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream13_1), toml::syntax_error);
|
||||
std::istringstream stream0_1(std::string("invalid-datetime = 2000-00-01"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream0_1), toml::syntax_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_date_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27",
|
||||
value(toml::local_date(1979, toml::month_t::May, 27)));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27", value(toml::local_date(1979, toml::month_t::May, 27)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_datetime)
|
||||
@@ -107,6 +215,11 @@ BOOST_AUTO_TEST_CASE(test_offset_datetime)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_offset_datetime, "1979-05-27T07:32:00.999999+09:00",
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
toml::local_time(7, 32, 0, 999, 999), toml::time_offset(9, 0)));
|
||||
|
||||
std::istringstream stream1(std::string("invalid-datetime = 2000-01-01T00:00:00+24:00"));
|
||||
std::istringstream stream2(std::string("invalid-datetime = 2000-01-01T00:00:00+00:60"));
|
||||
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_offset_datetime_value)
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
#define BOOST_TEST_MODULE "test_parse_file"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/example.toml");
|
||||
const auto data = toml::parse(testinput("example.toml"));
|
||||
|
||||
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
const auto owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
|
||||
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
|
||||
@@ -27,7 +23,7 @@ BOOST_AUTO_TEST_CASE(test_example)
|
||||
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
const auto database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
@@ -36,7 +32,7 @@ BOOST_AUTO_TEST_CASE(test_example)
|
||||
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
const auto servers = toml::find(data, "servers");
|
||||
{
|
||||
toml::table alpha = toml::find<toml::table>(servers, "alpha");
|
||||
BOOST_TEST(toml::get<std::string>(alpha.at("ip")) == "10.0.0.1");
|
||||
@@ -48,7 +44,7 @@ BOOST_AUTO_TEST_CASE(test_example)
|
||||
BOOST_TEST(toml::get<std::string>(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
const auto clients = toml::find(data, "clients");
|
||||
{
|
||||
toml::array clients_data = toml::find<toml::array>(clients, "data");
|
||||
|
||||
@@ -76,11 +72,11 @@ BOOST_AUTO_TEST_CASE(test_example)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_stream)
|
||||
{
|
||||
std::ifstream ifs("toml/tests/example.toml");
|
||||
std::ifstream ifs(testinput("example.toml"), std::ios::binary);
|
||||
const auto data = toml::parse(ifs);
|
||||
|
||||
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
const auto owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
|
||||
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
|
||||
@@ -91,7 +87,7 @@ BOOST_AUTO_TEST_CASE(test_example_stream)
|
||||
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
const auto database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
@@ -100,7 +96,7 @@ BOOST_AUTO_TEST_CASE(test_example_stream)
|
||||
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
const auto servers = toml::find(data, "servers");
|
||||
{
|
||||
toml::table alpha = toml::find<toml::table>(servers, "alpha");
|
||||
BOOST_TEST(toml::get<std::string>(alpha.at("ip")) == "10.0.0.1");
|
||||
@@ -112,7 +108,76 @@ BOOST_AUTO_TEST_CASE(test_example_stream)
|
||||
BOOST_TEST(toml::get<std::string>(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
const auto clients = toml::find(data, "clients");
|
||||
{
|
||||
toml::array clients_data = toml::find<toml::array>(clients, "data");
|
||||
std::vector<std::string> expected_name{"gamma", "delta"};
|
||||
BOOST_CHECK(toml::get<std::vector<std::string>>(clients_data.at(0)) == expected_name);
|
||||
|
||||
std::vector<int> expected_number{1, 2};
|
||||
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) == expected_number);
|
||||
|
||||
std::vector<std::string> expected_hosts{"alpha", "omega"};
|
||||
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") == expected_hosts);
|
||||
}
|
||||
|
||||
std::vector<toml::table> products =
|
||||
toml::find<std::vector<toml::table>>(data, "products");
|
||||
{
|
||||
BOOST_TEST(toml::get<std::string>(products.at(0).at("name")) ==
|
||||
"Hammer");
|
||||
BOOST_TEST(toml::get<std::int64_t>(products.at(0).at("sku")) ==
|
||||
738594937);
|
||||
|
||||
BOOST_TEST(toml::get<std::string>(products.at(1).at("name")) ==
|
||||
"Nail");
|
||||
BOOST_TEST(toml::get<std::int64_t>(products.at(1).at("sku")) ==
|
||||
284758393);
|
||||
BOOST_TEST(toml::get<std::string>(products.at(1).at("color")) ==
|
||||
"gray");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_file_pointer)
|
||||
{
|
||||
FILE * file = fopen(testinput("example.toml").c_str(), "rb");
|
||||
const auto data = toml::parse(file, "toml/tests/example.toml");
|
||||
fclose(file);
|
||||
|
||||
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
|
||||
const auto owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
|
||||
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
|
||||
BOOST_TEST(toml::find<std::string>(owner, "bio") ==
|
||||
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
|
||||
BOOST_TEST(toml::find<toml::offset_datetime>(owner, "dob") ==
|
||||
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
|
||||
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
|
||||
}
|
||||
|
||||
const auto database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
|
||||
BOOST_TEST(toml::find<int >(database, "connection_max") == 5000);
|
||||
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
|
||||
}
|
||||
|
||||
const auto servers = toml::find(data, "servers");
|
||||
{
|
||||
toml::table alpha = toml::find<toml::table>(servers, "alpha");
|
||||
BOOST_TEST(toml::get<std::string>(alpha.at("ip")) == "10.0.0.1");
|
||||
BOOST_TEST(toml::get<std::string>(alpha.at("dc")) == "eqdc10");
|
||||
|
||||
toml::table beta = toml::find<toml::table>(servers, "beta");
|
||||
BOOST_TEST(toml::get<std::string>(beta.at("ip")) == "10.0.0.2");
|
||||
BOOST_TEST(toml::get<std::string>(beta.at("dc")) == "eqdc10");
|
||||
BOOST_TEST(toml::get<std::string>(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD");
|
||||
}
|
||||
|
||||
const auto clients = toml::find(data, "clients");
|
||||
{
|
||||
toml::array clients_data = toml::find<toml::array>(clients, "data");
|
||||
std::vector<std::string> expected_name{"gamma", "delta"};
|
||||
@@ -144,7 +209,7 @@ BOOST_AUTO_TEST_CASE(test_example_stream)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_fruit)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/fruit.toml");
|
||||
const auto data = toml::parse(testinput("fruit.toml"));
|
||||
const auto blah = toml::find<toml::array>(toml::find(data, "fruit"), "blah");
|
||||
BOOST_TEST(toml::find<std::string>(blah.at(0), "name") == "apple");
|
||||
BOOST_TEST(toml::find<std::string>(blah.at(1), "name") == "banana");
|
||||
@@ -162,7 +227,7 @@ BOOST_AUTO_TEST_CASE(test_fruit)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/hard_example.toml");
|
||||
const auto data = toml::parse(testinput("hard_example.toml"));
|
||||
const auto the = toml::find(data, "the");
|
||||
BOOST_TEST(toml::find<std::string>(the, "test_string") ==
|
||||
"You'll hate me after this - #");
|
||||
@@ -189,7 +254,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/hard_example.toml");
|
||||
const auto data = toml::parse<toml::preserve_comments>(testinput("hard_example.toml"));
|
||||
const auto the = toml::find(data, "the");
|
||||
BOOST_TEST(toml::find<std::string>(the, "test_string") ==
|
||||
"You'll hate me after this - #");
|
||||
@@ -218,10 +283,10 @@ BOOST_AUTO_TEST_CASE(test_hard_example_comment)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
|
||||
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
|
||||
|
||||
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
const auto owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
|
||||
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
|
||||
@@ -234,7 +299,7 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
|
||||
" First class dates? Why not?");
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
const auto database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
@@ -243,15 +308,15 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
|
||||
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
const auto servers = toml::find(data, "servers");
|
||||
{
|
||||
const auto& alpha = toml::find(servers, "alpha");
|
||||
const auto alpha = toml::find(servers, "alpha");
|
||||
BOOST_TEST(alpha.comments().at(0) ==
|
||||
" You can indent as you please. Tabs or spaces. TOML don't care.");
|
||||
BOOST_TEST(toml::find<std::string>(alpha, "ip") == "10.0.0.1");
|
||||
BOOST_TEST(toml::find<std::string>(alpha, "dc") == "eqdc10");
|
||||
|
||||
const auto& beta = toml::find(servers, "beta");
|
||||
const auto beta = toml::find(servers, "beta");
|
||||
BOOST_TEST(toml::find<std::string>(beta, "ip") == "10.0.0.2");
|
||||
BOOST_TEST(toml::find<std::string>(beta, "dc") == "eqdc10");
|
||||
BOOST_TEST(toml::find<std::string>(beta, "country") ==
|
||||
@@ -260,7 +325,7 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
|
||||
" This should be parsed as UTF-8");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
const auto clients = toml::find(data, "clients");
|
||||
{
|
||||
BOOST_TEST(toml::find(clients, "data").comments().at(0) ==
|
||||
" just an update to make sure parsers support it");
|
||||
@@ -300,8 +365,8 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque
|
||||
>("toml/tests/example.toml");
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
|
||||
testinput("example.toml"));
|
||||
|
||||
static_assert(std::is_same<typename decltype(data)::table_type,
|
||||
std::map<toml::key, typename std::remove_cv<decltype(data)>::type>
|
||||
@@ -311,7 +376,7 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
|
||||
>::value, "");
|
||||
|
||||
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
|
||||
const auto& owner = toml::find(data, "owner");
|
||||
const auto owner = toml::find(data, "owner");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
|
||||
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
|
||||
@@ -324,7 +389,7 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
|
||||
" First class dates? Why not?");
|
||||
}
|
||||
|
||||
const auto& database = toml::find(data, "database");
|
||||
const auto database = toml::find(data, "database");
|
||||
{
|
||||
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
|
||||
const std::vector<int> expected_ports{8001, 8001, 8002};
|
||||
@@ -333,15 +398,15 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
|
||||
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
|
||||
}
|
||||
|
||||
const auto& servers = toml::find(data, "servers");
|
||||
const auto servers = toml::find(data, "servers");
|
||||
{
|
||||
const auto& alpha = toml::find(servers, "alpha");
|
||||
const auto alpha = toml::find(servers, "alpha");
|
||||
BOOST_TEST(alpha.comments().at(0) ==
|
||||
" You can indent as you please. Tabs or spaces. TOML don't care.");
|
||||
BOOST_TEST(toml::find<std::string>(alpha, "ip") == "10.0.0.1");
|
||||
BOOST_TEST(toml::find<std::string>(alpha, "dc") == "eqdc10");
|
||||
|
||||
const auto& beta = toml::find(servers, "beta");
|
||||
const auto beta = toml::find(servers, "beta");
|
||||
BOOST_TEST(toml::find<std::string>(beta, "ip") == "10.0.0.2");
|
||||
BOOST_TEST(toml::find<std::string>(beta, "dc") == "eqdc10");
|
||||
BOOST_TEST(toml::find<std::string>(beta, "country") ==
|
||||
@@ -350,7 +415,7 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
|
||||
" This should be parsed as UTF-8");
|
||||
}
|
||||
|
||||
const auto& clients = toml::find(data, "clients");
|
||||
const auto clients = toml::find(data, "clients");
|
||||
{
|
||||
BOOST_TEST(toml::find(clients, "data").comments().at(0) ==
|
||||
" just an update to make sure parsers support it");
|
||||
@@ -779,6 +844,22 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
|
||||
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
|
||||
|
||||
@@ -889,3 +970,40 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_file_ends_without_lf)
|
||||
{
|
||||
{
|
||||
const std::string table(
|
||||
"key = \"value\"\n"
|
||||
"[table]\n"
|
||||
"key = \"value\""
|
||||
);
|
||||
std::istringstream iss(table);
|
||||
const auto data = toml::parse(iss,
|
||||
"test_files_end_without_lf.toml");
|
||||
|
||||
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
|
||||
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_parse_function_compiles)
|
||||
{
|
||||
using result_type = decltype(toml::parse("string literal"));
|
||||
(void) [](const char* that) -> result_type { return toml::parse(that); };
|
||||
(void) [](char* that) -> result_type { return toml::parse(that); };
|
||||
(void) [](const std::string& that) -> result_type { return toml::parse(that); };
|
||||
(void) [](std::string& that) -> result_type { return toml::parse(that); };
|
||||
(void) [](std::string&& that) -> result_type { return toml::parse(that); };
|
||||
#ifdef TOML11_HAS_STD_FILESYSTEM
|
||||
(void) [](const std::filesystem::path& that) -> result_type { return toml::parse(that); };
|
||||
(void) [](std::filesystem::path& that) -> result_type { return toml::parse(that); };
|
||||
(void) [](std::filesystem::path&& that) -> result_type { return toml::parse(that); };
|
||||
#endif
|
||||
(void) [](std::FILE* that) -> result_type { return toml::parse(that, "mandatory.toml"); };
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_parse_nonexistent_file)
|
||||
{
|
||||
BOOST_CHECK_THROW(toml::parse("nonexistent.toml"), std::ios_base::failure);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
#define BOOST_TEST_MODULE "parse_floating_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
#include <cmath>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace toml;
|
||||
using namespace detail;
|
||||
|
||||
@@ -128,7 +124,7 @@ BOOST_AUTO_TEST_CASE(test_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);
|
||||
BOOST_CHECK(r.is_ok());
|
||||
BOOST_CHECK(std::isinf(r.unwrap().first));
|
||||
@@ -136,7 +132,7 @@ BOOST_AUTO_TEST_CASE(test_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);
|
||||
BOOST_CHECK(r.is_ok());
|
||||
BOOST_CHECK(std::isinf(r.unwrap().first));
|
||||
@@ -144,7 +140,7 @@ BOOST_AUTO_TEST_CASE(test_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);
|
||||
BOOST_CHECK(r.is_ok());
|
||||
BOOST_CHECK(std::isinf(r.unwrap().first));
|
||||
@@ -156,23 +152,30 @@ BOOST_AUTO_TEST_CASE(test_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);
|
||||
BOOST_CHECK(r.is_ok());
|
||||
BOOST_CHECK(std::isnan(r.unwrap().first));
|
||||
}
|
||||
{
|
||||
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);
|
||||
BOOST_CHECK(r.is_ok());
|
||||
BOOST_CHECK(std::isnan(r.unwrap().first));
|
||||
}
|
||||
{
|
||||
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);
|
||||
BOOST_CHECK(r.is_ok());
|
||||
BOOST_CHECK(std::isnan(r.unwrap().first));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_overflow)
|
||||
{
|
||||
std::istringstream float_overflow (std::string("float-overflow = 1.0e+1024"));
|
||||
BOOST_CHECK_THROW(toml::parse(float_overflow ), toml::syntax_error);
|
||||
// istringstream >> float does not set failbit in case of underflow.
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "parse_inline_table_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -13,19 +8,19 @@ using namespace detail;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_inline_table)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{}", table());
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table<toml::value>, "{}", table());
|
||||
{
|
||||
table t;
|
||||
t["foo"] = toml::value(42);
|
||||
t["bar"] = toml::value("baz");
|
||||
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{foo = 42, bar = \"baz\"}", t);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table<toml::value>, "{foo = 42, bar = \"baz\"}", t);
|
||||
}
|
||||
{
|
||||
table t;
|
||||
table t_sub;
|
||||
t_sub["name"] = toml::value("pug");
|
||||
t["type"] = toml::value(t_sub);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{type.name = \"pug\"}", t);
|
||||
TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table<toml::value>, "{type.name = \"pug\"}", t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "parse_integer_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -89,4 +84,33 @@ BOOST_AUTO_TEST_CASE(test_bin_value)
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b010000", value(16));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b01_00_00", value(16));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b111111", value(63));
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"0b1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000",
|
||||
// 1 0 0 0
|
||||
// 0 C 8 4
|
||||
value(0x0888888888888888));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"0b01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111",
|
||||
// 1 0 0 0
|
||||
// 0 C 8 4
|
||||
value(0x7FFFFFFFFFFFFFFF));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"0b00000000_01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111",
|
||||
// 1 0 0 0
|
||||
// 0 C 8 4
|
||||
value(0x7FFFFFFFFFFFFFFF));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_integer_overflow)
|
||||
{
|
||||
std::istringstream dec_overflow(std::string("dec-overflow = 9223372036854775808"));
|
||||
std::istringstream hex_overflow(std::string("hex-overflow = 0x1_00000000_00000000"));
|
||||
std::istringstream oct_overflow(std::string("oct-overflow = 0o1_000_000_000_000_000_000_000"));
|
||||
// 64 56 48 40 32 24 16 8
|
||||
std::istringstream bin_overflow(std::string("bin-overflow = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000"));
|
||||
BOOST_CHECK_THROW(toml::parse(dec_overflow), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(hex_overflow), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(oct_overflow), toml::syntax_error);
|
||||
BOOST_CHECK_THROW(toml::parse(bin_overflow), toml::syntax_error);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "parse_key_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "parse_string_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -29,16 +24,16 @@ BOOST_AUTO_TEST_CASE(test_string)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"The quick brown fox jumps over the lazy dog\"",
|
||||
toml::value("The quick brown fox jumps over the lazy dog", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\'The quick brown fox jumps over the lazy dog\'",
|
||||
toml::value("The quick brown fox jumps over the lazy dog", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"The quick brown fox \\\njumps over the lazy dog\"\"\"",
|
||||
toml::value("The quick brown fox jumps over the lazy dog", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''The quick brown fox \njumps over the lazy dog'''",
|
||||
toml::value("The quick brown fox \njumps over the lazy dog", string_t::literal));
|
||||
}
|
||||
@@ -69,14 +64,17 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\" And when \\\"'s are in the along with # \\\"\"",
|
||||
string(" And when \"'s are in the along with # \"", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"Here are fifteen apostrophes: '''''''''''''''\"",
|
||||
string("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_basic_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"GitHub Cofounder & CEO\\nLikes tater tots and beer.\"",
|
||||
value("GitHub Cofounder & CEO\nLikes tater tots and beer.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"192.168.1.1\"",
|
||||
value("192.168.1.1", string_t::basic));
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
@@ -84,16 +82,19 @@ BOOST_AUTO_TEST_CASE(test_basic_string_value)
|
||||
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"",
|
||||
value("\xE4\xB8\xAD\xE5\x9B\xBD", string_t::basic));
|
||||
#else
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"中国\"",
|
||||
value("中国", string_t::basic));
|
||||
#endif
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"You'll hate me after this - #\"",
|
||||
value("You'll hate me after this - #", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\" And when \\\"'s are in the along with # \\\"\"",
|
||||
value(" And when \"'s are in the along with # \"", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"Here are fifteen apostrophes: '''''''''''''''\"",
|
||||
value("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
||||
@@ -104,16 +105,41 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
|
||||
string("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
|
||||
string("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
|
||||
string("Here are three quotation marks: \"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
|
||||
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
|
||||
string("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ml_basic_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"\nThe quick brown \\\n\n fox jumps over \\\n the lazy dog.\"\"\"",
|
||||
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
|
||||
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
|
||||
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
|
||||
value("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
|
||||
value("Here are three quotation marks: \"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
|
||||
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
|
||||
value("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||
@@ -134,16 +160,16 @@ BOOST_AUTO_TEST_CASE(test_literal_string)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_literal_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'C:\\Users\\nodejs\\templates'",
|
||||
value("C:\\Users\\nodejs\\templates", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'\\\\ServerX\\admin$\\system32\\'",
|
||||
value("\\\\ServerX\\admin$\\system32\\", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'Tom \"Dubs\" Preston-Werner'",
|
||||
value("Tom \"Dubs\" Preston-Werner", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'<\\i\\c*\\s*>'",
|
||||
value("<\\i\\c*\\s*>", string_t::literal));
|
||||
}
|
||||
@@ -156,18 +182,49 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
|
||||
string("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"''''That's still pointless', she said.'''",
|
||||
string("'That's still pointless', she said.", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
|
||||
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
"''''This,' she said, 'is just a pointless statement.''''",
|
||||
string("'This,' she said, 'is just a pointless statement.'", string_t::literal));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ml_literal_string_value)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''I [dw]on't need \\d{2} apples'''",
|
||||
value("I [dw]on't need \\d{2} apples", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
|
||||
value("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"''''That's still pointless', she said.'''",
|
||||
value("'That's still pointless', she said.", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
|
||||
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
|
||||
"''''This,' she said, 'is just a pointless statement.''''",
|
||||
value("'This,' she said, 'is just a pointless statement.'", string_t::literal));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_simple_excape_sequences)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
R"("\"\\\b\f\n\r\t")",
|
||||
string("\"\\\b\f\n\r\t", string_t::basic));
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
TOML11_TEST_PARSE_EQUAL(parse_string,
|
||||
R"("\e")",
|
||||
string("\x1b", string_t::basic));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_unicode_escape_sequence)
|
||||
{
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
#define BOOST_TEST_MODULE "parse_table_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
#include <toml/get.hpp>
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
@@ -19,7 +14,7 @@ BOOST_AUTO_TEST_CASE(test_normal_table)
|
||||
"key2 = 42\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);
|
||||
BOOST_TEST(result.is_ok());
|
||||
@@ -36,7 +31,7 @@ BOOST_AUTO_TEST_CASE(test_nested_table)
|
||||
"a.b = \"value\"\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);
|
||||
BOOST_TEST(result.is_ok());
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#define BOOST_TEST_MODULE "parse_table_key_test"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/parser.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
#include "test_parse_aux.hpp"
|
||||
|
||||
using namespace toml;
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
#define BOOST_TEST_MODULE "test_parse_unicode"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
|
||||
const auto data = toml::parse(testinput("hard_example_unicode.toml"));
|
||||
|
||||
const auto the = toml::find<toml::table>(data, "the");
|
||||
BOOST_TEST(toml::get<std::string>(the.at("test_string")) ==
|
||||
@@ -40,35 +35,3 @@ BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
|
||||
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("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
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#define BOOST_TEST_MODULE "test_result"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <iostream>
|
||||
#include <toml/result.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_construct)
|
||||
{
|
||||
{
|
||||
@@ -437,5 +438,3 @@ BOOST_AUTO_TEST_CASE(test_and_or_other)
|
||||
BOOST_TEST("foo" == r1_gen().and_other(r2_gen()).unwrap_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
#define BOOST_TEST_MODULE "test_serialize_file"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
#include <clocale>
|
||||
|
||||
template<typename Comment,
|
||||
template<typename ...> class Table,
|
||||
@@ -46,7 +45,7 @@ bool has_comment_inside(const toml::basic_value<Comment, Table, Array>& v)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/example.toml");
|
||||
const auto data = toml::parse(testinput("example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp1.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -68,7 +67,7 @@ BOOST_AUTO_TEST_CASE(test_example)
|
||||
BOOST_AUTO_TEST_CASE(test_example_map_dq)
|
||||
{
|
||||
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
|
||||
"toml/tests/example.toml");
|
||||
testinput("example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp1_map_dq.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -90,7 +89,7 @@ BOOST_AUTO_TEST_CASE(test_example_map_dq)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_example_with_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
|
||||
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp1_com.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -116,7 +115,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment)
|
||||
BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
|
||||
{
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
|
||||
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp1_com_nocomment.toml");
|
||||
ofs << std::setw(80) << toml::nocomment << data;
|
||||
@@ -126,8 +125,8 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
|
||||
BOOST_TEST(!has_comment_inside(serialized));
|
||||
}
|
||||
{
|
||||
const auto data_nocomment = toml::parse("toml/tests/example.toml");
|
||||
auto serialized = toml::parse("tmp1_com_nocomment.toml");
|
||||
const auto data_nocomment = toml::parse<toml::discard_comments>(testinput("example.toml"));
|
||||
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_nocomment.toml");
|
||||
{
|
||||
auto& owner = toml::find(serialized, "owner");
|
||||
auto& bio = toml::find<std::string>(owner, "bio");
|
||||
@@ -145,7 +144,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
|
||||
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
|
||||
"toml/tests/example.toml");
|
||||
testinput("example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp1_com_map_dq.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -172,7 +171,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq)
|
||||
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
|
||||
{
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>("toml/tests/example.toml");
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(testinput("example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp1_com_map_dq_nocomment.toml");
|
||||
ofs << std::setw(80) << toml::nocomment << data;
|
||||
@@ -181,8 +180,8 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
|
||||
BOOST_TEST(!has_comment_inside(serialized));
|
||||
}
|
||||
{
|
||||
const auto data_nocomment = toml::parse("toml/tests/example.toml");
|
||||
auto serialized = toml::parse("tmp1_com_map_dq_nocomment.toml");
|
||||
const auto data_nocomment = toml::parse<toml::discard_comments>(testinput("example.toml"));
|
||||
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_map_dq_nocomment.toml");
|
||||
{
|
||||
auto& owner = toml::find(serialized, "owner");
|
||||
auto& bio = toml::find<std::string>(owner, "bio");
|
||||
@@ -198,7 +197,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_fruit)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/fruit.toml");
|
||||
const auto data = toml::parse(testinput("fruit.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp2.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -210,7 +209,7 @@ BOOST_AUTO_TEST_CASE(test_fruit)
|
||||
BOOST_AUTO_TEST_CASE(test_fruit_map_dq)
|
||||
{
|
||||
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
|
||||
"toml/tests/fruit.toml");
|
||||
testinput("fruit.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp2.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -222,7 +221,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_map_dq)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_fruit_with_comments)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments>("toml/tests/fruit.toml");
|
||||
const auto data = toml::parse<toml::preserve_comments>(testinput("fruit.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp2_com.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -234,7 +233,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_with_comments)
|
||||
BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
|
||||
"toml/tests/fruit.toml");
|
||||
testinput("fruit.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp2_com.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -245,7 +244,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example)
|
||||
{
|
||||
const auto data = toml::parse("toml/tests/hard_example.toml");
|
||||
const auto data = toml::parse(testinput("hard_example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp3.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -257,7 +256,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example_map_dq)
|
||||
{
|
||||
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
|
||||
"toml/tests/hard_example.toml");
|
||||
testinput("hard_example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp3.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -270,7 +269,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example_map_dq)
|
||||
BOOST_AUTO_TEST_CASE(test_hard_example_with_comment)
|
||||
{
|
||||
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
|
||||
"toml/tests/hard_example.toml");
|
||||
testinput("hard_example.toml"));
|
||||
{
|
||||
std::ofstream ofs("tmp3_com.toml");
|
||||
ofs << std::setw(80) << data;
|
||||
@@ -303,3 +302,104 @@ BOOST_AUTO_TEST_CASE(test_format_key)
|
||||
BOOST_TEST("\"special-chars-\\\\-\\\"-\\b-\\f-\\r-\\n-\\t\"" == toml::format_key(key));
|
||||
}
|
||||
}
|
||||
|
||||
// In toml11, an implicitly-defined value does not have any comments.
|
||||
// So, in the following file,
|
||||
// ```toml
|
||||
// # comment
|
||||
// [[array-of-tables]]
|
||||
// foo = "bar"
|
||||
// ```
|
||||
// The array named "array-of-tables" does not have the comment, but the first
|
||||
// element of the array has. That means that, the above file is equivalent to
|
||||
// the following.
|
||||
// ```toml
|
||||
// array-of-tables = [
|
||||
// # comment
|
||||
// {foo = "bar"},
|
||||
// ]
|
||||
// ```
|
||||
// If the array itself has a comment (value_has_comment_ == true), we should try
|
||||
// to make it inline.
|
||||
// ```toml
|
||||
// # comment about array
|
||||
// array-of-tables = [
|
||||
// # comment about table element
|
||||
// {foo = "bar"}
|
||||
// ]
|
||||
// ```
|
||||
// If it is formatted as a multiline table, the two comments becomes
|
||||
// indistinguishable.
|
||||
// ```toml
|
||||
// # comment about array
|
||||
// # comment about table element
|
||||
// [[array-of-tables]]
|
||||
// foo = "bar"
|
||||
// ```
|
||||
// So we need to try to make it inline, and it force-inlines regardless
|
||||
// of the line width limit.
|
||||
// It may fail if the element of a table has comment. In that case,
|
||||
// the array-of-tables will be formatted as a multiline table.
|
||||
BOOST_AUTO_TEST_CASE(test_distinguish_comment)
|
||||
{
|
||||
const std::string str = R"(# comment about array itself
|
||||
array_of_table = [
|
||||
# comment about the first element (table)
|
||||
{key = "value"},
|
||||
])";
|
||||
std::istringstream iss(str);
|
||||
const auto data = toml::parse<toml::preserve_comments>(iss);
|
||||
const auto serialized = toml::format(data, /*width = */ 0);
|
||||
|
||||
std::istringstream reparse(serialized);
|
||||
const auto parsed = toml::parse<toml::preserve_comments>(reparse);
|
||||
|
||||
BOOST_TEST(parsed.at("array_of_table").comments().size() == 1u);
|
||||
BOOST_TEST(parsed.at("array_of_table").comments().front() == " comment about array itself");
|
||||
BOOST_TEST(parsed.at("array_of_table").at(0).comments().size() == 1u);
|
||||
BOOST_TEST(parsed.at("array_of_table").at(0).comments().front() == " comment about the first element (table)");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_serialize_under_locale)
|
||||
{
|
||||
// avoid null init (setlocale returns null when it failed)
|
||||
std::string setloc(std::setlocale(LC_ALL, nullptr));
|
||||
|
||||
// fr_FR is a one of locales that uses `,` as a decimal separator.
|
||||
if(const char* try_hyphen = std::setlocale(LC_ALL, "fr_FR.UTF-8"))
|
||||
{
|
||||
setloc = std::string(try_hyphen);
|
||||
}
|
||||
else if(const char* try_nohyphen = std::setlocale(LC_ALL, "fr_FR.utf8"))
|
||||
{
|
||||
setloc = std::string(try_nohyphen);
|
||||
}
|
||||
// In some envs, fr_FR locale has not been installed. Tests must work even in such a case.
|
||||
// else
|
||||
// {
|
||||
// BOOST_TEST(false);
|
||||
// }
|
||||
BOOST_TEST_MESSAGE("current locale at the beginning of the test = " << setloc);
|
||||
|
||||
const std::string str = R"(
|
||||
pi = 3.14159
|
||||
large_int = 1234567890
|
||||
)";
|
||||
std::istringstream iss(str);
|
||||
const auto ref = toml::parse(iss);
|
||||
const auto serialized_str = toml::format(ref, /*width = */ 80);
|
||||
|
||||
BOOST_TEST_MESSAGE("serialized = " << serialized_str);
|
||||
|
||||
std::istringstream serialized_iss(serialized_str);
|
||||
const auto serialized_ref = toml::parse(serialized_iss);
|
||||
|
||||
BOOST_TEST(serialized_ref.at("pi").as_floating() == ref.at("pi").as_floating());
|
||||
BOOST_TEST(serialized_ref.at("large_int").as_integer() == ref.at("large_int").as_integer());
|
||||
|
||||
const std::string endloc(std::setlocale(LC_ALL, nullptr));
|
||||
BOOST_TEST_MESSAGE("current locale at the end of the test = " << endloc);
|
||||
// check if serializer change global locale
|
||||
BOOST_TEST(setloc == endloc);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define BOOST_TEST_MODULE "test_string"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_basic_string)
|
||||
{
|
||||
{
|
||||
@@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(test_string_add_assign)
|
||||
str += str2;
|
||||
BOOST_TEST(str.str == "foobar");
|
||||
}
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
// std::string_view
|
||||
{
|
||||
toml::string str("foo");
|
||||
@@ -151,4 +151,3 @@ BOOST_AUTO_TEST_CASE(test_string_add_assign)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
#define BOOST_TEST_MODULE "test_traits"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/types.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <forward_list>
|
||||
#include <deque>
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
|
||||
struct dummy_type{};
|
||||
|
||||
|
||||
@@ -1,35 +1,28 @@
|
||||
#define BOOST_TEST_MODULE "test_acceptor"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml/utility.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_resize)
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_try_reserve)
|
||||
{
|
||||
{
|
||||
typedef std::vector<int> resizable_type;
|
||||
typedef std::array<int,1> non_resizable_type;
|
||||
BOOST_TEST(toml::detail::has_resize_method<resizable_type>::value);
|
||||
BOOST_TEST(!toml::detail::has_resize_method<non_resizable_type>::value);
|
||||
// since BOOST_TEST is a macro, it cannot handle commas correctly.
|
||||
// When toml::detail::has_reserve_method<std::array<int, 1>>::value
|
||||
// is passed to a macro, C preprocessor considers
|
||||
// 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;
|
||||
toml::resize(v, 10);
|
||||
BOOST_TEST(v.size() == 10u);
|
||||
}
|
||||
{
|
||||
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);
|
||||
toml::try_reserve(v, 100);
|
||||
BOOST_TEST(v.capacity() == 100u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#define BOOST_TEST_MODULE "test_value"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
@@ -423,7 +419,7 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_TEST(v2.as_boolean() == true);
|
||||
BOOST_TEST(v3.as_boolean() == true);
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
std::string_view sv = "foo";
|
||||
|
||||
toml::value v7(sv);
|
||||
@@ -966,3 +962,54 @@ BOOST_AUTO_TEST_CASE(test_value_bracket)
|
||||
BOOST_CHECK_THROW(v1["foo"], toml::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_map_methods)
|
||||
{
|
||||
{
|
||||
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
|
||||
|
||||
BOOST_TEST(v1.count("foo") == 1u);
|
||||
BOOST_TEST(v1.count("bar") == 1u);
|
||||
BOOST_TEST(v1.count("baz") == 1u);
|
||||
BOOST_TEST(v1.count("qux") == 0u);
|
||||
|
||||
BOOST_TEST( v1.contains("foo"));
|
||||
BOOST_TEST( v1.contains("bar"));
|
||||
BOOST_TEST( v1.contains("baz"));
|
||||
BOOST_TEST(!v1.contains("qux"));
|
||||
|
||||
BOOST_TEST(v1.size() == 3);
|
||||
|
||||
v1["qux"] = 54;
|
||||
BOOST_TEST(v1.count("qux") == 1u);
|
||||
BOOST_TEST(v1.contains("qux"));
|
||||
BOOST_TEST(v1.size() == 4);
|
||||
}
|
||||
{
|
||||
toml::value v1(42);
|
||||
BOOST_CHECK_THROW(v1.size() , toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.count("k") , toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.contains("k"), toml::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_vector_methods)
|
||||
{
|
||||
{
|
||||
toml::value v1{1, 2, 3, 4, 5};
|
||||
|
||||
BOOST_TEST(v1.size() == 5);
|
||||
|
||||
v1.push_back(6);
|
||||
BOOST_TEST(v1.size() == 6);
|
||||
|
||||
v1.emplace_back(6);
|
||||
BOOST_TEST(v1.size() == 7);
|
||||
}
|
||||
{
|
||||
toml::value v1(42);
|
||||
BOOST_CHECK_THROW(v1.size(), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.push_back(1), toml::type_error);
|
||||
BOOST_CHECK_THROW(v1.emplace_back(1), toml::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
23
tests/unit_test.hpp
Normal file
23
tests/unit_test.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef BOOST_TEST_MODULE
|
||||
# error "Please #define BOOST_TEST_MODULE before you #include <unit_test.hpp>"
|
||||
#endif
|
||||
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
# include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
# include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
static inline auto testinput(const std::string& basename) -> std::string
|
||||
{
|
||||
const auto this_or_that = [](const char *const s, const char *const t) { return s ? s : t; };
|
||||
std::string directory = this_or_that(std::getenv("TOMLDIR"), "toml");
|
||||
if (!directory.empty() && directory.back() != '/')
|
||||
{
|
||||
directory.push_back('/');
|
||||
}
|
||||
return directory.append("tests/").append(basename);
|
||||
}
|
||||
11
toml.hpp
11
toml.hpp
@@ -25,17 +25,14 @@
|
||||
#ifndef TOML_FOR_MODERN_CPP
|
||||
#define TOML_FOR_MODERN_CPP
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error "__cplusplus is not defined"
|
||||
#endif
|
||||
|
||||
#if __cplusplus < 201103L && _MSC_VER < 1900
|
||||
# error "toml11 requires C++11 or later."
|
||||
#endif
|
||||
#define TOML11_VERSION_MAJOR 3
|
||||
#define TOML11_VERSION_MINOR 8
|
||||
#define TOML11_VERSION_PATCH 1
|
||||
|
||||
#include "toml/parser.hpp"
|
||||
#include "toml/literal.hpp"
|
||||
#include "toml/serializer.hpp"
|
||||
#include "toml/get.hpp"
|
||||
#include "toml/macros.hpp"
|
||||
|
||||
#endif// TOML_FOR_MODERN_CPP
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef TOML11_COLOR_HPP
|
||||
#define TOML11_COLOR_HPP
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
#ifdef TOML11_COLORIZE_ERROR_MESSAGE
|
||||
#define TOML11_ERROR_MESSAGE_COLORIZED true
|
||||
@@ -17,11 +17,41 @@ namespace color_ansi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline int colorize_index()
|
||||
{
|
||||
static const int index = std::ios_base::xalloc();
|
||||
return index;
|
||||
}
|
||||
|
||||
// Control color mode globally
|
||||
class color_mode
|
||||
{
|
||||
public:
|
||||
inline void enable()
|
||||
{
|
||||
should_color_ = true;
|
||||
}
|
||||
inline void disable()
|
||||
{
|
||||
should_color_ = false;
|
||||
}
|
||||
|
||||
inline bool should_color() const
|
||||
{
|
||||
return should_color_;
|
||||
}
|
||||
|
||||
static color_mode& status()
|
||||
{
|
||||
static color_mode status_;
|
||||
return status_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool should_color_ = false;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
inline std::ostream& colorize(std::ostream& os)
|
||||
@@ -55,6 +85,21 @@ inline std::ostream& cyan (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
|
||||
inline std::ostream& white (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
|
||||
|
||||
inline void enable()
|
||||
{
|
||||
return detail::color_mode::status().enable();
|
||||
}
|
||||
inline void disable()
|
||||
{
|
||||
return detail::color_mode::status().disable();
|
||||
}
|
||||
|
||||
inline bool should_color()
|
||||
{
|
||||
return detail::color_mode::status().should_color();
|
||||
}
|
||||
|
||||
} // color_ansi
|
||||
|
||||
// ANSI escape sequence is the only and default colorization method currently
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef 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 <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.
|
||||
// when they fail, it does not change the location.
|
||||
@@ -27,7 +29,7 @@ namespace detail
|
||||
// to output character as an error message.
|
||||
inline std::string show_char(const char c)
|
||||
{
|
||||
// It supress an error that occurs only in Debug mode of MSVC++ on Windows.
|
||||
// It suppresses an error that occurs only in Debug mode of MSVC++ on Windows.
|
||||
// I'm not completely sure but they check the value of char to be in the
|
||||
// range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
|
||||
// has negative value (if char has sign). So here it re-interprets c as
|
||||
@@ -56,13 +58,9 @@ struct character
|
||||
{
|
||||
static constexpr char target = C;
|
||||
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& 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();}
|
||||
const auto first = loc.iter();
|
||||
|
||||
@@ -73,7 +71,7 @@ struct character
|
||||
}
|
||||
loc.advance(); // update location
|
||||
|
||||
return ok(region<Cont>(loc, first, loc.iter()));
|
||||
return ok(region(loc, first, loc.iter()));
|
||||
}
|
||||
};
|
||||
template<char C>
|
||||
@@ -89,13 +87,9 @@ struct in_range
|
||||
static constexpr char upper = Up;
|
||||
static constexpr char lower = Low;
|
||||
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& 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();}
|
||||
const auto first = loc.iter();
|
||||
|
||||
@@ -106,7 +100,7 @@ struct in_range
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -117,13 +111,9 @@ template<char L, char U> constexpr char in_range<L, U>::lower;
|
||||
template<typename Combinator>
|
||||
struct exclude
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& 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();}
|
||||
auto first = loc.iter();
|
||||
|
||||
@@ -134,7 +124,7 @@ struct exclude
|
||||
return none();
|
||||
}
|
||||
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>
|
||||
struct maybe
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& 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);
|
||||
if(rslt.is_ok())
|
||||
{
|
||||
return rslt;
|
||||
}
|
||||
return ok(region<Cont>(loc));
|
||||
return ok(region(loc));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -164,15 +150,11 @@ struct sequence;
|
||||
template<typename Head, typename ... Tail>
|
||||
struct sequence<Head, Tail...>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& 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 rslt = Head::invoke(loc);
|
||||
auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
loc.reset(first);
|
||||
@@ -182,9 +164,9 @@ struct sequence<Head, Tail...>
|
||||
}
|
||||
|
||||
// called from the above function only, recursively.
|
||||
template<typename Cont, typename Iterator>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
||||
template<typename Iterator>
|
||||
static result<region, none_t>
|
||||
invoke(location& loc, region reg, Iterator first)
|
||||
{
|
||||
const auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
@@ -201,9 +183,9 @@ template<typename Head>
|
||||
struct sequence<Head>
|
||||
{
|
||||
// would be called from sequence<T ...>::invoke only.
|
||||
template<typename Cont, typename Iterator>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
||||
template<typename Iterator>
|
||||
static result<region, none_t>
|
||||
invoke(location& loc, region reg, Iterator first)
|
||||
{
|
||||
const auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
@@ -222,13 +204,9 @@ struct either;
|
||||
template<typename Head, typename ... Tail>
|
||||
struct either<Head, Tail...>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& 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);
|
||||
if(rslt.is_ok()) {return rslt;}
|
||||
return either<Tail...>::invoke(loc);
|
||||
@@ -237,12 +215,9 @@ struct either<Head, Tail...>
|
||||
template<typename Head>
|
||||
struct either<Head>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& loc)
|
||||
{
|
||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||
"internal error: container::value_type should be `char`.");
|
||||
return Head::invoke(loc);
|
||||
}
|
||||
};
|
||||
@@ -257,11 +232,10 @@ struct unlimited{};
|
||||
template<typename T, std::size_t N>
|
||||
struct repeat<T, exactly<N>>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& loc)
|
||||
{
|
||||
region<Cont> retval(loc);
|
||||
region retval(loc);
|
||||
const auto first = loc.iter();
|
||||
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>
|
||||
struct repeat<T, at_least<N>>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& loc)
|
||||
{
|
||||
region<Cont> retval(loc);
|
||||
region retval(loc);
|
||||
|
||||
const auto first = loc.iter();
|
||||
for(std::size_t i=0; i<N; ++i)
|
||||
@@ -312,11 +285,10 @@ struct repeat<T, at_least<N>>
|
||||
template<typename T>
|
||||
struct repeat<T, unlimited>
|
||||
{
|
||||
template<typename Cont>
|
||||
static result<region<Cont>, none_t>
|
||||
invoke(location<Cont>& loc)
|
||||
static result<region, none_t>
|
||||
invoke(location& loc)
|
||||
{
|
||||
region<Cont> retval(loc);
|
||||
region retval(loc);
|
||||
while(true)
|
||||
{
|
||||
auto rslt = T::invoke(loc);
|
||||
|
||||
@@ -2,12 +2,19 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_COMMENTS_HPP
|
||||
#define TOML11_COMMENTS_HPP
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
|
||||
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
|
||||
#else
|
||||
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
|
||||
#endif
|
||||
|
||||
// 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>`
|
||||
@@ -81,6 +88,54 @@ struct preserve_comments
|
||||
void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}
|
||||
void assign(size_type n, const std::string& val) {comments.assign(n, val);}
|
||||
|
||||
// Related to the issue #97.
|
||||
//
|
||||
// It is known that `std::vector::insert` and `std::vector::erase` in
|
||||
// the standard library implementation included in GCC 4.8.5 takes
|
||||
// `std::vector::iterator` instead of `std::vector::const_iterator`.
|
||||
// Because of the const-correctness, we cannot convert a `const_iterator` to
|
||||
// an `iterator`. It causes compilation error in GCC 4.8.5.
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
|
||||
# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
|
||||
# define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
|
||||
iterator insert(iterator p, const std::string& x)
|
||||
{
|
||||
return comments.insert(p, x);
|
||||
}
|
||||
iterator insert(iterator p, std::string&& x)
|
||||
{
|
||||
return comments.insert(p, std::move(x));
|
||||
}
|
||||
void insert(iterator p, size_type n, const std::string& x)
|
||||
{
|
||||
return comments.insert(p, n, x);
|
||||
}
|
||||
template<typename InputIterator>
|
||||
void insert(iterator p, InputIterator first, InputIterator last)
|
||||
{
|
||||
return comments.insert(p, first, last);
|
||||
}
|
||||
void insert(iterator p, std::initializer_list<std::string> ini)
|
||||
{
|
||||
return comments.insert(p, ini);
|
||||
}
|
||||
|
||||
template<typename ... Ts>
|
||||
iterator emplace(iterator p, Ts&& ... args)
|
||||
{
|
||||
return comments.emplace(p, std::forward<Ts>(args)...);
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) {return comments.erase(pos);}
|
||||
iterator erase(iterator first, iterator last)
|
||||
{
|
||||
return comments.erase(first, last);
|
||||
}
|
||||
#else
|
||||
iterator insert(const_iterator p, const std::string& x)
|
||||
{
|
||||
return comments.insert(p, x);
|
||||
@@ -114,6 +169,7 @@ struct preserve_comments
|
||||
{
|
||||
return comments.erase(first, last);
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(preserve_comments& other) {comments.swap(other.comments);}
|
||||
|
||||
@@ -290,7 +346,7 @@ operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::differ
|
||||
//
|
||||
// Why this is chose as the default type is because the last version (2.x.y)
|
||||
// does not contain any comments in a value. To minimize the impact on the
|
||||
// efficiency, this is choosed as a default.
|
||||
// efficiency, this is chosen as a default.
|
||||
//
|
||||
// To reduce the memory footprint, later we can try empty base optimization (EBO).
|
||||
struct discard_comments
|
||||
@@ -369,14 +425,14 @@ struct discard_comments
|
||||
// empty, so accessing through operator[], front/back, data causes address
|
||||
// error.
|
||||
|
||||
reference operator[](const size_type) noexcept {return *data();}
|
||||
const_reference operator[](const size_type) const noexcept {return *data();}
|
||||
reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}
|
||||
const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}
|
||||
reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||
const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||
reference front() noexcept {return *data();}
|
||||
const_reference front() const noexcept {return *data();}
|
||||
reference back() noexcept {return *data();}
|
||||
const_reference back() const noexcept {return *data();}
|
||||
reference front() noexcept {never_call("toml::discard_comment::front");}
|
||||
const_reference front() const noexcept {never_call("toml::discard_comment::front");}
|
||||
reference back() noexcept {never_call("toml::discard_comment::back");}
|
||||
const_reference back() const noexcept {never_call("toml::discard_comment::back");}
|
||||
|
||||
pointer data() noexcept {return nullptr;}
|
||||
const_pointer data() const noexcept {return nullptr;}
|
||||
@@ -394,6 +450,18 @@ struct discard_comments
|
||||
const_reverse_iterator rend() const noexcept {return const_iterator{};}
|
||||
const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
|
||||
const_reverse_iterator crend() const noexcept {return const_iterator{};}
|
||||
|
||||
private:
|
||||
|
||||
[[noreturn]] static void never_call(const char *const this_function)
|
||||
{
|
||||
#ifdef __has_builtin
|
||||
# if __has_builtin(__builtin_unreachable)
|
||||
__builtin_unreachable();
|
||||
# endif
|
||||
#endif
|
||||
throw std::logic_error{this_function};
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_DATETIME_HPP
|
||||
#define TOML11_DATETIME_HPP
|
||||
#include <chrono>
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <ostream>
|
||||
#include <iomanip>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
@@ -20,22 +21,7 @@ namespace toml
|
||||
namespace detail
|
||||
{
|
||||
// TODO: find more sophisticated way to handle this
|
||||
#if _POSIX_C_SOURCE >= 1 || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::localtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
inline std::tm gmtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::gmtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
#elif _MSC_VER
|
||||
#if defined(_MSC_VER)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
@@ -50,6 +36,21 @@ inline std::tm gmtime_s(const std::time_t* src)
|
||||
if (result) { throw std::runtime_error("gmtime_s failed."); }
|
||||
return dst;
|
||||
}
|
||||
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::localtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
inline std::tm gmtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::gmtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
#else // fallback. not threadsafe
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
@@ -84,9 +85,9 @@ enum class month_t : std::uint8_t
|
||||
|
||||
struct local_date
|
||||
{
|
||||
std::int16_t year; // A.D. (like, 2018)
|
||||
std::uint8_t month; // [0, 11]
|
||||
std::uint8_t day; // [1, 31]
|
||||
std::int16_t year{}; // A.D. (like, 2018)
|
||||
std::uint8_t month{}; // [0, 11]
|
||||
std::uint8_t day{}; // [1, 31]
|
||||
|
||||
local_date(int y, month_t m, int d)
|
||||
: year (static_cast<std::int16_t>(y)),
|
||||
@@ -172,20 +173,20 @@ template<typename charT, typename traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
|
||||
{
|
||||
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
|
||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month + 1) << '-';
|
||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day );
|
||||
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
|
||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
|
||||
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ) ;
|
||||
return os;
|
||||
}
|
||||
|
||||
struct local_time
|
||||
{
|
||||
std::uint8_t hour; // [0, 23]
|
||||
std::uint8_t minute; // [0, 59]
|
||||
std::uint8_t second; // [0, 60]
|
||||
std::uint16_t millisecond; // [0, 999]
|
||||
std::uint16_t microsecond; // [0, 999]
|
||||
std::uint16_t nanosecond; // [0, 999]
|
||||
std::uint8_t hour{}; // [0, 23]
|
||||
std::uint8_t minute{}; // [0, 59]
|
||||
std::uint8_t second{}; // [0, 60]
|
||||
std::uint16_t millisecond{}; // [0, 999]
|
||||
std::uint16_t microsecond{}; // [0, 999]
|
||||
std::uint16_t nanosecond{}; // [0, 999]
|
||||
|
||||
local_time(int h, int m, int s,
|
||||
int ms = 0, int us = 0, int ns = 0)
|
||||
@@ -296,8 +297,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_time& time)
|
||||
|
||||
struct time_offset
|
||||
{
|
||||
std::int8_t hour; // [-12, 12]
|
||||
std::int8_t minute; // [-59, 59]
|
||||
std::int8_t hour{}; // [-12, 12]
|
||||
std::int8_t minute{}; // [-59, 59]
|
||||
|
||||
time_offset(int h, int m)
|
||||
: hour (static_cast<std::int8_t>(h)),
|
||||
@@ -363,8 +364,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
|
||||
|
||||
struct local_datetime
|
||||
{
|
||||
local_date date;
|
||||
local_time time;
|
||||
local_date date{};
|
||||
local_time time{};
|
||||
|
||||
local_datetime(local_date d, local_time t): date(d), time(t) {}
|
||||
|
||||
@@ -477,9 +478,9 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_datetime& dt)
|
||||
|
||||
struct offset_datetime
|
||||
{
|
||||
local_date date;
|
||||
local_time time;
|
||||
time_offset offset;
|
||||
local_date date{};
|
||||
local_time time{};
|
||||
time_offset offset{};
|
||||
|
||||
offset_datetime(local_date d, local_time t, time_offset o)
|
||||
: date(d), time(t), offset(o)
|
||||
|
||||
@@ -2,17 +2,36 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_EXCEPTION_HPP
|
||||
#define TOML11_EXCEPTION_HPP
|
||||
#include "source_location.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "source_location.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
struct file_io_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
file_io_error(int errnum, const std::string& msg, const std::string& fname)
|
||||
: std::runtime_error(msg + " \"" + fname + "\": errno = " + std::to_string(errnum)),
|
||||
errno_(errnum)
|
||||
{}
|
||||
|
||||
int get_errno() const noexcept {return errno_;}
|
||||
|
||||
private:
|
||||
int errno_;
|
||||
};
|
||||
|
||||
struct exception : public std::exception
|
||||
{
|
||||
public:
|
||||
exception(const source_location& loc): loc_(loc) {}
|
||||
explicit exception(const source_location& loc): loc_(loc) {}
|
||||
virtual ~exception() noexcept override = default;
|
||||
virtual const char* what() const noexcept override {return "";}
|
||||
virtual source_location const& location() const noexcept {return loc_;}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_FROM_HPP
|
||||
#define TOML11_FROM_HPP
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
400
toml/get.hpp
400
toml/get.hpp
@@ -2,10 +2,11 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_GET_HPP
|
||||
#define TOML11_GET_HPP
|
||||
#include <algorithm>
|
||||
|
||||
#include "from.hpp"
|
||||
#include "result.hpp"
|
||||
#include "value.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -139,7 +140,7 @@ get(basic_value<C, M, V>&& v)
|
||||
// ============================================================================
|
||||
// std::string_view
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
inline detail::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
|
||||
@@ -188,8 +189,7 @@ get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
throw type_error(detail::format_underline("toml::value: "
|
||||
"bad_cast to std::chrono::system_clock::time_point", {
|
||||
{std::addressof(detail::get_region(v)),
|
||||
concat_to_string("the actual type is ", v.type())}
|
||||
{v.location(), concat_to_string("the actual type is ", v.type())}
|
||||
}), v.location());
|
||||
}
|
||||
}
|
||||
@@ -198,24 +198,25 @@ get(const basic_value<C, M, V>& v)
|
||||
// ============================================================================
|
||||
// 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 ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::has_resize_method<T>, // T::resize(N) works
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::has_push_back_method<T>, // T::push_back(value) works
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
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 ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::negation<detail::has_resize_method<T>>, // no T::resize() exists
|
||||
detail::negation< // not toml::array
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
|
||||
detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
||||
detail::negation< // not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>&);
|
||||
@@ -255,9 +256,36 @@ get(const basic_value<C, M, V>&);
|
||||
|
||||
// toml::from<T>::from_toml(v)
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
std::size_t S = sizeof(::toml::from<T>)>
|
||||
T get(const basic_value<C, M, V>&);
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(const basic_value<C, M, V>&);
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(basic_value<C, M, V>&);
|
||||
|
||||
// T(const toml::value&) and T is not toml::basic_value,
|
||||
// and it does not have `from<T>` nor `from_toml`.
|
||||
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>&>,
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
||||
detail::negation<detail::has_specialized_from<T>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, 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, basic_value<C, M, V>&>,
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
||||
detail::negation<detail::has_specialized_from<T>>
|
||||
>::value, T>
|
||||
get(basic_value<C, M, V>&);
|
||||
|
||||
// ============================================================================
|
||||
// array-like types; most likely STL container, like std::vector, etc.
|
||||
@@ -265,31 +293,55 @@ T get(const basic_value<C, M, V>&);
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::has_resize_method<T>, // T::resize(N) works
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::has_push_back_method<T>, // container.push_back(elem) works
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
using value_type = typename T::value_type;
|
||||
const auto& ar = v.as_array();
|
||||
const auto& ary = v.as_array();
|
||||
|
||||
T container;
|
||||
container.resize(ar.size());
|
||||
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
||||
[](const value& x){return ::toml::get<value_type>(x);});
|
||||
try_reserve(container, ary.size());
|
||||
|
||||
for(const auto& elem : ary)
|
||||
{
|
||||
container.push_back(get<value_type>(elem));
|
||||
}
|
||||
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 ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::negation<detail::has_resize_method<T>>, // no T::resize() exists
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back
|
||||
detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
||||
detail::negation< // T is not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
@@ -303,11 +355,13 @@ get(const basic_value<C, M, V>& v)
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"toml::get: specified container size is ", container.size(),
|
||||
" 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(),
|
||||
[](const value& x){return ::toml::get<value_type>(x);});
|
||||
for(std::size_t i=0; i<ar.size(); ++i)
|
||||
{
|
||||
container[i] = ::toml::get<value_type>(ar[i]);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
@@ -327,9 +381,7 @@ get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"toml::get: specified std::pair but there are ", ar.size(),
|
||||
" elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
" elements in toml array."), {{v.location(), "here"}}));
|
||||
}
|
||||
return std::make_pair(::toml::get<first_type >(ar.at(0)),
|
||||
::toml::get<second_type>(ar.at(1)));
|
||||
@@ -359,9 +411,7 @@ get(const basic_value<C, M, V>& v)
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"toml::get: specified std::tuple with ",
|
||||
std::tuple_size<T>::value, " elements, but there are ", ar.size(),
|
||||
" elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
" elements in toml array."), {{v.location(), "here"}}));
|
||||
}
|
||||
return detail::get_tuple_impl<T>(ar,
|
||||
detail::make_index_sequence<std::tuple_size<T>::value>{});
|
||||
@@ -387,7 +437,7 @@ get(const basic_value<C, M, V>& v)
|
||||
T map;
|
||||
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;
|
||||
}
|
||||
@@ -410,12 +460,45 @@ get(const basic_value<C, M, V>& v)
|
||||
return ud;
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
std::size_t>
|
||||
T get(const basic_value<C, M, V>& v)
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
return ::toml::from<T>::from_toml(v);
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(basic_value<C, M, V>& v)
|
||||
{
|
||||
return ::toml::from<T>::from_toml(v);
|
||||
}
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::negation<detail::is_basic_value<T>>, // T is not a toml::value
|
||||
std::is_constructible<T, const basic_value<C, M, V>&>, // T is constructible from toml::value
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
||||
detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
return T(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>>, // T is not a toml::value
|
||||
std::is_constructible<T, basic_value<C, M, V>&>, // T is constructible from toml::value
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
||||
detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
||||
>::value, T>
|
||||
get(basic_value<C, M, V>& v)
|
||||
{
|
||||
return T(v);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// find
|
||||
@@ -429,10 +512,7 @@ basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
||||
const auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
}
|
||||
return tab.at(ky);
|
||||
}
|
||||
@@ -443,10 +523,7 @@ basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
||||
auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
}
|
||||
return tab.at(ky);
|
||||
}
|
||||
@@ -457,14 +534,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();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
detail::throw_key_not_found_error(v, 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);
|
||||
|
||||
@@ -476,10 +590,7 @@ find(const basic_value<C, M, V>& v, const key& ky)
|
||||
const auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
}
|
||||
return ::toml::get<T>(tab.at(ky));
|
||||
}
|
||||
@@ -492,10 +603,7 @@ find(basic_value<C, M, V>& v, const key& ky)
|
||||
auto& tab = v.as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
detail::throw_key_not_found_error(v, ky);
|
||||
}
|
||||
return ::toml::get<T>(tab.at(ky));
|
||||
}
|
||||
@@ -508,65 +616,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();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
detail::throw_key_not_found_error(v, 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)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// It suppresses warnings by -Wsign-conversion. Let's say we have the following
|
||||
// code.
|
||||
// ```cpp
|
||||
// const auto x = toml::find<std::string>(data, "array", 0);
|
||||
// ```
|
||||
// Here, the type of literal number `0` is `int`. `int` is a signed integer.
|
||||
// `toml::find` takes `std::size_t` as an index. So it causes implicit sign
|
||||
// conversion and `-Wsign-conversion` warns about it. Using `0u` instead of `0`
|
||||
// suppresses the warning, but it makes user code messy.
|
||||
// To suppress this warning, we need to be aware of type conversion caused
|
||||
// by `toml::find(v, key1, key2, ... keys)`. But the thing is that the types of
|
||||
// keys can be any combination of {string-like, size_t-like}. Of course we can't
|
||||
// write down all the combinations. Thus we need to use some function that
|
||||
// recognize the type of argument and cast it into `std::string` or
|
||||
// `std::size_t` depending on the context.
|
||||
// `key_cast` does the job. It has 2 overloads. One is invoked when the
|
||||
// argument type is an integer and cast the argument into `std::size_t`. The
|
||||
// other is invoked when the argument type is not an integer, possibly one of
|
||||
// std::string, const char[N] or const char*, and construct std::string from
|
||||
// the argument.
|
||||
// `toml::find(v, k1, k2, ... ks)` uses `key_cast` before passing `ks` to
|
||||
// `toml::find(v, k)` to suppress -Wsign-conversion.
|
||||
|
||||
template<typename T>
|
||||
enable_if_t<conjunction<std::is_integral<remove_cvref_t<T>>,
|
||||
negation<std::is_same<remove_cvref_t<T>, bool>>>::value, std::size_t>
|
||||
key_cast(T&& v) noexcept
|
||||
{
|
||||
return std::size_t(v);
|
||||
}
|
||||
template<typename T>
|
||||
enable_if_t<negation<conjunction<std::is_integral<remove_cvref_t<T>>,
|
||||
negation<std::is_same<remove_cvref_t<T>, bool>>>>::value, std::string>
|
||||
key_cast(T&& v) noexcept
|
||||
{
|
||||
return std::string(std::forward<T>(v));
|
||||
}
|
||||
} // detail
|
||||
|
||||
template<typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
const basic_value<C, M, V>&
|
||||
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||
{
|
||||
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
return ::toml::find(::toml::find(v, detail::key_cast(k1)),
|
||||
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||
}
|
||||
template<typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
basic_value<C, M, V>&
|
||||
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||
{
|
||||
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
return ::toml::find(::toml::find(v, detail::key_cast(k1)),
|
||||
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||
}
|
||||
template<typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
basic_value<C, M, V>
|
||||
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||
{
|
||||
return ::toml::find(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
|
||||
return ::toml::find(::toml::find(std::move(v), std::forward<Key1>(k1)),
|
||||
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>()))
|
||||
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||
{
|
||||
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
|
||||
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
||||
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||
{
|
||||
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
|
||||
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
typename Key1, typename Key2, typename ... Keys>
|
||||
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
||||
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
|
||||
{
|
||||
return ::toml::find<T>(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
|
||||
return ::toml::find<T>(::toml::find(std::move(v), detail::key_cast(k1)),
|
||||
detail::key_cast(k2), std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -881,6 +1075,50 @@ find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
||||
return get_or(tab.at(ky), std::forward<T>(opt));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// recursive find-or with type deduction (find_or(value, keys, opt))
|
||||
|
||||
template<typename Value, typename ... Ks,
|
||||
typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
||||
// here we need to add SFINAE in the template parameter to avoid
|
||||
// infinite recursion in type deduction on gcc
|
||||
auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
||||
-> decltype(find_or(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
||||
{
|
||||
if(!v.is_table())
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
auto&& tab = std::forward<Value>(v).as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// recursive find_or with explicit type specialization, find_or<int>(value, keys...)
|
||||
|
||||
template<typename T, typename Value, typename ... Ks,
|
||||
typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
||||
// here we need to add SFINAE in the template parameter to avoid
|
||||
// infinite recursion in type deduction on gcc
|
||||
auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
||||
-> decltype(find_or<T>(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
||||
{
|
||||
if(!v.is_table())
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
auto&& tab = std::forward<Value>(v).as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// expect
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_INTO_HPP
|
||||
#define TOML11_INTO_HPP
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
130
toml/lexer.hpp
130
toml/lexer.hpp
@@ -2,11 +2,11 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_LEXER_HPP
|
||||
#define TOML11_LEXER_HPP
|
||||
#include "combinator.hpp"
|
||||
#include <stdexcept>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "combinator.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -69,15 +69,8 @@ using lex_zero_prefixable_int = sequence<lex_digit, repeat<either<lex_digit,
|
||||
|
||||
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'>>,
|
||||
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,
|
||||
sequence<lex_dec_int, either<lex_exponent_part,
|
||||
@@ -125,17 +118,11 @@ using lex_local_time = lex_partial_time;
|
||||
// ===========================================================================
|
||||
|
||||
using lex_quotation_mark = character<'"'>;
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab)
|
||||
in_range<0x0a, 0x1F>, // is allowed
|
||||
character<0x22>, character<0x5C>,
|
||||
character<0x7F>>>;
|
||||
#else
|
||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x1F>,
|
||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab) is allowed
|
||||
in_range<0x0A, 0x1F>,
|
||||
character<0x22>, character<0x5C>,
|
||||
character<0x7F>>>;
|
||||
|
||||
#endif
|
||||
using lex_escape = character<'\\'>;
|
||||
using lex_escape_unicode_short = sequence<character<'u'>,
|
||||
repeat<lex_hex_dig, exactly<4>>>;
|
||||
@@ -145,6 +132,9 @@ using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
|
||||
character<'b'>, character<'f'>,
|
||||
character<'n'>, character<'r'>,
|
||||
character<'t'>,
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
character<'e'>, // ESC (0x1B)
|
||||
#endif
|
||||
lex_escape_unicode_short,
|
||||
lex_escape_unicode_long
|
||||
>;
|
||||
@@ -154,19 +144,47 @@ using lex_basic_string = sequence<lex_quotation_mark,
|
||||
repeat<lex_basic_char, unlimited>,
|
||||
lex_quotation_mark>;
|
||||
|
||||
// After toml post-v0.5.0, it is explicitly clarified how quotes in ml-strings
|
||||
// are allowed to be used.
|
||||
// After this, the following strings are *explicitly* allowed.
|
||||
// - One or two `"`s in a multi-line basic string is allowed wherever it is.
|
||||
// - Three consecutive `"`s in a multi-line basic string is considered as a delimiter.
|
||||
// - One or two `"`s can appear just before or after the delimiter.
|
||||
// ```toml
|
||||
// str4 = """Here are two quotation marks: "". Simple enough."""
|
||||
// str5 = """Here are three quotation marks: ""\"."""
|
||||
// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
|
||||
// str7 = """"This," she said, "is just a pointless statement.""""
|
||||
// ```
|
||||
// In the current implementation (v3.3.0), it is difficult to parse `str7` in
|
||||
// the above example. It is difficult to recognize `"` at the end of string body
|
||||
// collectly. It will be misunderstood as a `"""` delimiter and an additional,
|
||||
// invalid `"`. Like this:
|
||||
// ```console
|
||||
// what(): [error] toml::parse_table: invalid line format
|
||||
// --> hoge.toml
|
||||
// |
|
||||
// 13 | str7 = """"This," she said, "is just a pointless statement.""""
|
||||
// | ^- expected newline, but got '"'.
|
||||
// ```
|
||||
// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
|
||||
// split 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>>;
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09
|
||||
in_range<0x0a, 0x1F>, // is tab
|
||||
character<0x5C>,
|
||||
character<0x7F>,
|
||||
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 is tab
|
||||
in_range<0x0A, 0x1F>,
|
||||
character<0x5C>, // backslash
|
||||
character<0x7F>, // DEL
|
||||
lex_ml_basic_string_delim>>;
|
||||
#else // TOML v0.5.0
|
||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00,0x1F>,
|
||||
character<0x5C>,
|
||||
character<0x7F>,
|
||||
lex_ml_basic_string_delim>>;
|
||||
#endif
|
||||
|
||||
using lex_ml_basic_escaped_newline = sequence<
|
||||
lex_escape, maybe<lex_ws>, lex_newline,
|
||||
@@ -176,39 +194,39 @@ using lex_ml_basic_char = either<lex_ml_basic_unescaped, lex_escaped>;
|
||||
using lex_ml_basic_body = repeat<either<lex_ml_basic_char, lex_newline,
|
||||
lex_ml_basic_escaped_newline>,
|
||||
unlimited>;
|
||||
using lex_ml_basic_string = sequence<lex_ml_basic_string_delim,
|
||||
using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
|
||||
lex_ml_basic_body,
|
||||
lex_ml_basic_string_delim>;
|
||||
lex_ml_basic_string_close>;
|
||||
|
||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
in_range<0x10, 0x19>, character<0x27>>>;
|
||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>, in_range<0x0A, 0x1F>,
|
||||
character<0x7F>, character<0x27>>>;
|
||||
using lex_apostrophe = character<'\''>;
|
||||
using lex_literal_string = sequence<lex_apostrophe,
|
||||
repeat<lex_literal_char, unlimited>,
|
||||
lex_apostrophe>;
|
||||
|
||||
// the same reason as above.
|
||||
using lex_ml_literal_string_delim = repeat<lex_apostrophe, exactly<3>>;
|
||||
using lex_ml_literal_string_open = lex_ml_literal_string_delim;
|
||||
using lex_ml_literal_string_close = sequence<
|
||||
repeat<lex_apostrophe, exactly<3>>,
|
||||
maybe<lex_apostrophe>, maybe<lex_apostrophe>
|
||||
>;
|
||||
|
||||
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
in_range<0x10, 0x1F>,
|
||||
in_range<0x0A, 0x1F>,
|
||||
character<0x7F>,
|
||||
lex_ml_literal_string_delim>>;
|
||||
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
|
||||
unlimited>;
|
||||
using lex_ml_literal_string = sequence<lex_ml_literal_string_delim,
|
||||
using lex_ml_literal_string = sequence<lex_ml_literal_string_open,
|
||||
lex_ml_literal_body,
|
||||
lex_ml_literal_string_delim>;
|
||||
lex_ml_literal_string_close>;
|
||||
|
||||
using lex_string = either<lex_ml_basic_string, lex_basic_string,
|
||||
lex_ml_literal_string, lex_literal_string>;
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
using lex_comment_start_symbol = character<'#'>;
|
||||
using lex_non_eol = either<character<'\t'>, exclude<in_range<0x00, 0x19>>>;
|
||||
using lex_comment = sequence<lex_comment_start_symbol,
|
||||
repeat<lex_non_eol, unlimited>>;
|
||||
|
||||
using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
|
||||
|
||||
using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
|
||||
@@ -243,6 +261,34 @@ using lex_array_table = sequence<lex_array_table_open,
|
||||
maybe<lex_ws>,
|
||||
lex_array_table_close>;
|
||||
|
||||
using lex_utf8_1byte = in_range<0x00, 0x7F>;
|
||||
using lex_utf8_2byte = sequence<
|
||||
in_range<'\xC2', '\xDF'>,
|
||||
in_range<'\x80', '\xBF'>
|
||||
>;
|
||||
using lex_utf8_3byte = sequence<either<
|
||||
sequence<character<'\xE0'>, in_range<'\xA0', '\xBF'>>,
|
||||
sequence<in_range<'\xE1', '\xEC'>, in_range<'\x80', '\xBF'>>,
|
||||
sequence<character<'\xED'>, in_range<'\x80', '\x9F'>>,
|
||||
sequence<in_range<'\xEE', '\xEF'>, in_range<'\x80', '\xBF'>>
|
||||
>, in_range<'\x80', '\xBF'>>;
|
||||
using lex_utf8_4byte = sequence<either<
|
||||
sequence<character<'\xF0'>, in_range<'\x90', '\xBF'>>,
|
||||
sequence<in_range<'\xF1', '\xF3'>, in_range<'\x80', '\xBF'>>,
|
||||
sequence<character<'\xF4'>, in_range<'\x80', '\x8F'>>
|
||||
>, in_range<'\x80', '\xBF'>, in_range<'\x80', '\xBF'>>;
|
||||
using lex_utf8_code = either<
|
||||
lex_utf8_1byte,
|
||||
lex_utf8_2byte,
|
||||
lex_utf8_3byte,
|
||||
lex_utf8_4byte
|
||||
>;
|
||||
|
||||
using lex_comment_start_symbol = character<'#'>;
|
||||
using lex_non_eol_ascii = either<character<0x09>, in_range<0x20, 0x7E>>;
|
||||
using lex_comment = sequence<lex_comment_start_symbol, repeat<either<
|
||||
lex_non_eol_ascii, lex_utf8_2byte, lex_utf8_3byte, lex_utf8_4byte>, unlimited>>;
|
||||
|
||||
} // detail
|
||||
} // toml
|
||||
#endif // TOML_LEXER_HPP
|
||||
|
||||
@@ -11,12 +11,12 @@ inline namespace literals
|
||||
inline namespace toml_literals
|
||||
{
|
||||
|
||||
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||
// implementation
|
||||
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||
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));
|
||||
|
||||
using value_type = ::toml::basic_value<
|
||||
TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
|
||||
// if there are some comments or empty lines, skip them.
|
||||
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
|
||||
::toml::detail::maybe<::toml::detail::lex_ws>,
|
||||
@@ -53,7 +53,7 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||
// If it is neither a table-key or a array-of-table-key, it may be a value.
|
||||
if(!is_table_key && !is_aots_key)
|
||||
{
|
||||
if(auto data = ::toml::detail::parse_value<::toml::value>(loc))
|
||||
if(auto data = ::toml::detail::parse_value<value_type>(loc, 0))
|
||||
{
|
||||
return data.unwrap();
|
||||
}
|
||||
@@ -70,17 +70,43 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||
// It is a valid toml file.
|
||||
// It should be parsed as if we parse a file with this content.
|
||||
|
||||
if(auto data = ::toml::detail::parse_toml_file<::toml::value>(loc))
|
||||
if(auto data = ::toml::detail::parse_toml_file<value_type>(loc))
|
||||
{
|
||||
return data.unwrap();
|
||||
}
|
||||
else // none of them.
|
||||
{
|
||||
throw ::toml::syntax_error(data.unwrap_err(),
|
||||
source_location(std::addressof(loc)));
|
||||
throw ::toml::syntax_error(data.unwrap_err(), source_location(loc));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||
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));
|
||||
// literal length does not include the null character at the end.
|
||||
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::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||
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
|
||||
} // literals
|
||||
} // toml
|
||||
|
||||
121
toml/macros.hpp
Normal file
121
toml/macros.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#ifndef TOML11_MACROS_HPP
|
||||
#define TOML11_MACROS_HPP
|
||||
|
||||
#define TOML11_STRINGIZE_AUX(x) #x
|
||||
#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x)
|
||||
|
||||
#define TOML11_CONCATENATE_AUX(x, y) x##y
|
||||
#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y)
|
||||
|
||||
// ============================================================================
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
|
||||
|
||||
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TOML11_ARGS_SIZE
|
||||
|
||||
#define TOML11_INDEX_RSEQ() \
|
||||
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
|
||||
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define TOML11_ARGS_SIZE_IMPL(\
|
||||
ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, \
|
||||
ARG11, ARG12, ARG13, ARG14, ARG15, ARG16, ARG17, ARG18, ARG19, ARG20, \
|
||||
ARG21, ARG22, ARG23, ARG24, ARG25, ARG26, ARG27, ARG28, ARG29, ARG30, \
|
||||
ARG31, ARG32, N, ...) N
|
||||
#define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__)
|
||||
#define TOML11_ARGS_SIZE(...) TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ())
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TOML11_FOR_EACH_VA_ARGS
|
||||
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, ARG1 ) FUNCTOR(ARG1)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__)
|
||||
|
||||
#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
|
||||
TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
|
||||
|
||||
// use it in the following way.
|
||||
// ```cpp
|
||||
// namespace foo
|
||||
// {
|
||||
// struct Foo
|
||||
// {
|
||||
// std::string s;
|
||||
// double d;
|
||||
// int i;
|
||||
// };
|
||||
// } // foo
|
||||
//
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
|
||||
// ```
|
||||
// And then you can use `toml::find<foo::Foo>(file, "foo");`
|
||||
//
|
||||
#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\
|
||||
obj.VAR_NAME = toml::find<decltype(obj.VAR_NAME)>(v, TOML11_STRINGIZE(VAR_NAME));
|
||||
|
||||
#define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\
|
||||
v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME;
|
||||
|
||||
#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
|
||||
namespace toml { \
|
||||
template<> \
|
||||
struct from<NAME> \
|
||||
{ \
|
||||
template<typename C, template<typename ...> class T, \
|
||||
template<typename ...> class A> \
|
||||
static NAME from_toml(const basic_value<C, T, A>& v) \
|
||||
{ \
|
||||
NAME obj; \
|
||||
TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
|
||||
return obj; \
|
||||
} \
|
||||
}; \
|
||||
template<> \
|
||||
struct into<NAME> \
|
||||
{ \
|
||||
static value into_toml(const NAME& obj) \
|
||||
{ \
|
||||
::toml::value v = ::toml::table{}; \
|
||||
TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \
|
||||
return v; \
|
||||
} \
|
||||
}; \
|
||||
} /* toml */
|
||||
|
||||
#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||
|
||||
#endif// TOML11_MACROS_HPP
|
||||
1360
toml/parser.hpp
1360
toml/parser.hpp
File diff suppressed because it is too large
Load Diff
161
toml/region.hpp
161
toml/region.hpp
@@ -55,7 +55,7 @@ struct region_base
|
||||
// number of characters in the line after the region
|
||||
virtual std::size_t after() const noexcept {return 0;}
|
||||
|
||||
virtual std::vector<std::string> comments()const {return {};}
|
||||
virtual std::vector<std::string> comments() const {return {};}
|
||||
// ```toml
|
||||
// # comment_before
|
||||
// key = "value" # comment_inline
|
||||
@@ -67,22 +67,21 @@ struct region_base
|
||||
//
|
||||
// it contains pointer to the file content and iterator that points the current
|
||||
// location.
|
||||
template<typename Container>
|
||||
struct location final : public region_base
|
||||
{
|
||||
using const_iterator = typename Container::const_iterator;
|
||||
using difference_type = typename const_iterator::difference_type;
|
||||
using source_ptr = std::shared_ptr<const Container>;
|
||||
using const_iterator = typename std::vector<char>::const_iterator;
|
||||
using difference_type = typename std::iterator_traits<const_iterator>::difference_type;
|
||||
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");
|
||||
|
||||
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 source_name, std::vector<char> cont)
|
||||
: source_(std::make_shared<std::vector<char>>(std::move(cont))),
|
||||
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
|
||||
{}
|
||||
location(std::string source_name, const std::string& cont)
|
||||
: source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
|
||||
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
|
||||
{}
|
||||
|
||||
location(const location&) = default;
|
||||
location(location&&) = default;
|
||||
location& operator=(const location&) = default;
|
||||
@@ -93,7 +92,7 @@ struct location final : public region_base
|
||||
char front() const noexcept override {return *iter_;}
|
||||
|
||||
// this const prohibits codes like `++(loc.iter())`.
|
||||
const const_iterator iter() const noexcept {return iter_;}
|
||||
std::add_const<const_iterator>::type iter() const noexcept {return iter_;}
|
||||
|
||||
const_iterator begin() const noexcept {return source_->cbegin();}
|
||||
const_iterator end() const noexcept {return source_->cend();}
|
||||
@@ -195,33 +194,27 @@ struct location final : public region_base
|
||||
//
|
||||
// it contains pointer to the file content and iterator that points the first
|
||||
// and last location.
|
||||
template<typename Container>
|
||||
struct region final : public region_base
|
||||
{
|
||||
using const_iterator = typename Container::const_iterator;
|
||||
using source_ptr = std::shared_ptr<const Container>;
|
||||
|
||||
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");
|
||||
using const_iterator = typename std::vector<char>::const_iterator;
|
||||
using source_ptr = std::shared_ptr<const std::vector<char>>;
|
||||
|
||||
// delete default constructor. source_ never be null.
|
||||
region() = delete;
|
||||
|
||||
region(const location<Container>& loc)
|
||||
explicit region(const location& loc)
|
||||
: source_(loc.source()), source_name_(loc.name()),
|
||||
first_(loc.iter()), last_(loc.iter())
|
||||
{}
|
||||
region(location<Container>&& loc)
|
||||
explicit region(location&& loc)
|
||||
: source_(loc.source()), source_name_(loc.name()),
|
||||
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)
|
||||
{}
|
||||
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)
|
||||
{}
|
||||
|
||||
@@ -234,8 +227,7 @@ struct region final : public region_base
|
||||
region& operator+=(const region& other)
|
||||
{
|
||||
// different regions cannot be concatenated
|
||||
assert(this->begin() == other.begin() && this->end() == other.end() &&
|
||||
this->last_ == other.first_);
|
||||
assert(this->source_ == other.source_ && this->last_ == other.first_);
|
||||
|
||||
this->last_ = other.last_;
|
||||
return *this;
|
||||
@@ -350,9 +342,9 @@ struct region final : public region_base
|
||||
}))
|
||||
{
|
||||
// unwrap the first '#' by std::next.
|
||||
auto str = make_string(std::next(comment_found), iter);
|
||||
if(str.back() == '\r') {str.pop_back();}
|
||||
com.push_back(std::move(str));
|
||||
auto s = make_string(std::next(comment_found), iter);
|
||||
if(!s.empty() && s.back() == '\r') {s.pop_back();}
|
||||
com.push_back(std::move(s));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -403,9 +395,9 @@ struct region final : public region_base
|
||||
}))
|
||||
{
|
||||
// unwrap the first '#' by std::next.
|
||||
auto str = make_string(std::next(comment_found), this->line_end());
|
||||
if(str.back() == '\r') {str.pop_back();}
|
||||
com.push_back(std::move(str));
|
||||
auto s = make_string(std::next(comment_found), this->line_end());
|
||||
if(!s.empty() && s.back() == '\r') {s.pop_back();}
|
||||
com.push_back(std::move(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,107 +411,6 @@ struct region final : public region_base
|
||||
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 << ' ' << color::bold << color::blue << std::setw(line_num_width)
|
||||
<< std::right << 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
|
||||
} // toml
|
||||
#endif// TOML11_REGION_H
|
||||
|
||||
@@ -2,11 +2,22 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_SERIALIZER_HPP
|
||||
#define TOML11_SERIALIZER_HPP
|
||||
#include "value.hpp"
|
||||
#include "lexer.hpp"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <locale.h>
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <xlocale.h>
|
||||
#elif defined(__linux__)
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include "lexer.hpp"
|
||||
#include "value.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
@@ -22,39 +33,82 @@ namespace toml
|
||||
// Since toml restricts characters available in a bare key, generally a string
|
||||
// should be escaped. But checking whether a string needs to be surrounded by
|
||||
// a `"` and escaping some special character is boring.
|
||||
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>& k)
|
||||
{
|
||||
detail::location<toml::key> loc(key, key);
|
||||
if(k.empty())
|
||||
{
|
||||
return std::string("\"\"");
|
||||
}
|
||||
|
||||
// check the key can be a bare (unquoted) key
|
||||
detail::location loc(k, std::vector<char>(k.begin(), k.end()));
|
||||
detail::lex_unquoted_key::invoke(loc);
|
||||
if(loc.iter() == loc.end())
|
||||
{
|
||||
return key; // all the tokens are consumed. the key is unquoted-key.
|
||||
return k; // all the tokens are consumed. the key is unquoted-key.
|
||||
}
|
||||
std::string token("\"");
|
||||
for(const char c : key)
|
||||
|
||||
//if it includes special characters, then format it in a "quoted" key.
|
||||
std::basic_string<charT, traits, Alloc> serialized("\"");
|
||||
for(const char c : k)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case '\\': {token += "\\\\"; break;}
|
||||
case '\"': {token += "\\\""; break;}
|
||||
case '\b': {token += "\\b"; break;}
|
||||
case '\t': {token += "\\t"; break;}
|
||||
case '\f': {token += "\\f"; break;}
|
||||
case '\n': {token += "\\n"; break;}
|
||||
case '\r': {token += "\\r"; break;}
|
||||
default : {token += c; break;}
|
||||
case '\\': {serialized += "\\\\"; break;}
|
||||
case '\"': {serialized += "\\\""; break;}
|
||||
case '\b': {serialized += "\\b"; break;}
|
||||
case '\t': {serialized += "\\t"; break;}
|
||||
case '\f': {serialized += "\\f"; break;}
|
||||
case '\n': {serialized += "\\n"; break;}
|
||||
case '\r': {serialized += "\\r"; break;}
|
||||
default: {
|
||||
if (c >= 0x00 && c < 0x20)
|
||||
{
|
||||
std::array<char, 7> buf;
|
||||
std::snprintf(buf.data(), buf.size(), "\\u00%02x", static_cast<int>(c));
|
||||
serialized += buf.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
serialized += c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
token += "\"";
|
||||
return token;
|
||||
serialized += "\"";
|
||||
return serialized;
|
||||
}
|
||||
|
||||
template<typename Comment,
|
||||
template<typename ...> class Table,
|
||||
template<typename ...> class Array>
|
||||
template<typename charT, typename traits, typename Alloc>
|
||||
std::basic_string<charT, traits, Alloc>
|
||||
format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
|
||||
{
|
||||
if(keys.empty())
|
||||
{
|
||||
return std::string("\"\"");
|
||||
}
|
||||
|
||||
std::basic_string<charT, traits, Alloc> 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
|
||||
{
|
||||
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 comment_type = typename value_type::comment_type ;
|
||||
using boolean_type = typename value_type::boolean_type ;
|
||||
@@ -72,8 +126,10 @@ struct serializer
|
||||
const int float_prec = std::numeric_limits<toml::floating>::max_digits10,
|
||||
const bool can_be_inlined = false,
|
||||
const bool no_comment = false,
|
||||
std::vector<toml::key> ks = {})
|
||||
std::vector<toml::key> ks = {},
|
||||
const bool value_has_comment = false)
|
||||
: can_be_inlined_(can_be_inlined), no_comment_(no_comment),
|
||||
value_has_comment_(value_has_comment && !no_comment),
|
||||
float_prec_(float_prec), width_(w), keys_(std::move(ks))
|
||||
{}
|
||||
~serializer() = default;
|
||||
@@ -84,18 +140,93 @@ struct serializer
|
||||
}
|
||||
std::string operator()(const integer_type i) const
|
||||
{
|
||||
return std::to_string(i);
|
||||
#if defined(_WIN32)
|
||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
|
||||
locale_t original_locale(0);
|
||||
if(c_locale != locale_t(0))
|
||||
{
|
||||
original_locale = uselocale(c_locale);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto str = std::to_string(i);
|
||||
|
||||
#if defined(_WIN32)
|
||||
setlocale(LC_NUMERIC, original_locale.c_str());
|
||||
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
if(original_locale != locale_t(0))
|
||||
{
|
||||
uselocale(original_locale);
|
||||
}
|
||||
#endif
|
||||
return str;
|
||||
}
|
||||
std::string operator()(const floating_type f) const
|
||||
{
|
||||
if(std::isnan(f))
|
||||
{
|
||||
if(std::signbit(f))
|
||||
{
|
||||
return std::string("-nan");
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("nan");
|
||||
}
|
||||
}
|
||||
else if(!std::isfinite(f))
|
||||
{
|
||||
if(std::signbit(f))
|
||||
{
|
||||
return std::string("-inf");
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("inf");
|
||||
}
|
||||
}
|
||||
|
||||
// set locale to "C".
|
||||
// To make it thread-local, we use OS-specific features.
|
||||
// If we set process-global locale, it can break other thread that also
|
||||
// outputs something simultaneously.
|
||||
#if defined(_WIN32)
|
||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
|
||||
locale_t original_locale(0);
|
||||
if(c_locale != locale_t(0))
|
||||
{
|
||||
original_locale = uselocale(c_locale);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto fmt = "%.*g";
|
||||
const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
|
||||
// +1 for null character(\0)
|
||||
std::vector<char> buf(static_cast<std::size_t>(bsz + 1), '\0');
|
||||
std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
|
||||
|
||||
// restore the original locale
|
||||
#if defined(_WIN32)
|
||||
setlocale(LC_NUMERIC, original_locale.c_str());
|
||||
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
if(original_locale != locale_t(0))
|
||||
{
|
||||
uselocale(original_locale);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string token(buf.begin(), std::prev(buf.end()));
|
||||
if(token.back() == '.') // 1. => 1.0
|
||||
if(!token.empty() && token.back() == '.') // 1. => 1.0
|
||||
{
|
||||
token += '0';
|
||||
}
|
||||
@@ -112,35 +243,6 @@ struct serializer
|
||||
{
|
||||
// the resulting value does not have any float specific part!
|
||||
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;
|
||||
}
|
||||
@@ -148,12 +250,24 @@ struct serializer
|
||||
{
|
||||
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()) &&
|
||||
this->width_ != (std::numeric_limits<std::size_t>::max)())
|
||||
{
|
||||
// if linefeed is contained, make it multiline-string.
|
||||
const std::string open("\"\"\"\n");
|
||||
const std::string close("\\\n\"\"\"");
|
||||
return open + this->escape_ml_basic_string(s.str) + close;
|
||||
// if linefeed or double-quote is contained,
|
||||
// make it multiline basic string.
|
||||
const auto escaped = this->escape_ml_basic_string(s.str);
|
||||
std::string open("\"\"\"");
|
||||
std::string close("\"\"\"");
|
||||
if(escaped.find('\n') != std::string::npos ||
|
||||
this->width_ < escaped.size() + 6)
|
||||
{
|
||||
// if the string body contains newline or is enough long,
|
||||
// add newlines after and before delimiters.
|
||||
open += "\n";
|
||||
close = std::string("\\\n") + close;
|
||||
}
|
||||
return open + escaped + close;
|
||||
}
|
||||
|
||||
// no linefeed. try to make it oneline-string.
|
||||
@@ -194,7 +308,11 @@ struct serializer
|
||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||
std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
|
||||
{
|
||||
const std::string open("'''\n");
|
||||
std::string open("'''");
|
||||
if(this->width_ + 6 < s.str.size())
|
||||
{
|
||||
open += '\n'; // the first newline is ignored by TOML spec
|
||||
}
|
||||
const std::string close("'''");
|
||||
return open + s.str + close;
|
||||
}
|
||||
@@ -233,92 +351,18 @@ struct serializer
|
||||
|
||||
std::string operator()(const array_type& v) const
|
||||
{
|
||||
if(!v.empty() && v.front().is_table())// v is an array of tables
|
||||
{
|
||||
// if it's not inlined, we need to add `[[table.key]]`.
|
||||
// but if it can be inlined,
|
||||
// ```
|
||||
// table.key = [
|
||||
// {...},
|
||||
// # comment
|
||||
// {...},
|
||||
// ]
|
||||
// ```
|
||||
if(this->can_be_inlined_)
|
||||
{
|
||||
std::string token;
|
||||
if(!keys_.empty())
|
||||
{
|
||||
token += this->serialize_key(keys_.back());
|
||||
token += " = ";
|
||||
}
|
||||
bool failed = false;
|
||||
token += "[\n";
|
||||
for(const auto& item : v)
|
||||
{
|
||||
// if an element of the table has a comment, the table
|
||||
// cannot be inlined.
|
||||
if(this->has_comment_inside(item.as_table()))
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
if(!no_comment_)
|
||||
{
|
||||
for(const auto& c : item.comments())
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
const auto t = this->make_inline_table(item.as_table());
|
||||
|
||||
if(t.size() + 1 > width_ || // +1 for the last comma {...},
|
||||
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
token += t;
|
||||
token += ",\n";
|
||||
}
|
||||
if(!failed)
|
||||
{
|
||||
token += "]\n";
|
||||
return token;
|
||||
}
|
||||
// if failed, serialize them as [[array.of.tables]].
|
||||
}
|
||||
|
||||
std::string token;
|
||||
for(const auto& item : v)
|
||||
{
|
||||
if(!no_comment_)
|
||||
{
|
||||
for(const auto& c : item.comments())
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
token += "[[";
|
||||
token += this->serialize_dotted_key(keys_);
|
||||
token += "]]\n";
|
||||
token += this->make_multiline_table(item.as_table());
|
||||
}
|
||||
return token;
|
||||
}
|
||||
if(v.empty())
|
||||
{
|
||||
return std::string("[]");
|
||||
}
|
||||
if(this->is_array_of_tables(v))
|
||||
{
|
||||
return make_array_of_tables(v);
|
||||
}
|
||||
|
||||
// not an array of tables. normal array.
|
||||
// first, try to make it inline if none of the elements have a comment.
|
||||
if(!this->has_comment_inside(v))
|
||||
if( ! this->has_comment_inside(v))
|
||||
{
|
||||
const auto inl = this->make_inline_array(v);
|
||||
if(inl.size() < this->width_ &&
|
||||
@@ -339,7 +383,7 @@ struct serializer
|
||||
token += "[\n";
|
||||
for(const auto& item : v)
|
||||
{
|
||||
if(!item.comments().empty() && !no_comment_)
|
||||
if( ! item.comments().empty() && !no_comment_)
|
||||
{
|
||||
// if comment exists, the element must be the only element in the line.
|
||||
// e.g. the following is not allowed.
|
||||
@@ -365,15 +409,25 @@ struct serializer
|
||||
token += '\n';
|
||||
}
|
||||
token += toml::visit(*this, item);
|
||||
if(token.back() == '\n') {token.pop_back();}
|
||||
if(!token.empty() && token.back() == '\n') {token.pop_back();}
|
||||
token += ",\n";
|
||||
continue;
|
||||
}
|
||||
std::string next_elem;
|
||||
next_elem += toml::visit(*this, item);
|
||||
if(item.is_table())
|
||||
{
|
||||
serializer ser(*this);
|
||||
ser.can_be_inlined_ = true;
|
||||
ser.width_ = (std::numeric_limits<std::size_t>::max)();
|
||||
next_elem += toml::visit(ser, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
next_elem += toml::visit(*this, item);
|
||||
}
|
||||
|
||||
// comma before newline.
|
||||
if(next_elem.back() == '\n') {next_elem.pop_back();}
|
||||
if(!next_elem.empty() && next_elem.back() == '\n') {next_elem.pop_back();}
|
||||
|
||||
// if current line does not exceeds the width limit, continue.
|
||||
if(current_line.size() + next_elem.size() + 1 < this->width_)
|
||||
@@ -400,7 +454,10 @@ struct serializer
|
||||
}
|
||||
if(!current_line.empty())
|
||||
{
|
||||
if(current_line.back() != '\n') {current_line += '\n';}
|
||||
if(!current_line.empty() && current_line.back() != '\n')
|
||||
{
|
||||
current_line += '\n';
|
||||
}
|
||||
token += current_line;
|
||||
}
|
||||
token += "]\n";
|
||||
@@ -417,7 +474,7 @@ struct serializer
|
||||
std::string token;
|
||||
if(!this->keys_.empty())
|
||||
{
|
||||
token += this->serialize_key(this->keys_.back());
|
||||
token += format_key(this->keys_.back());
|
||||
token += " = ";
|
||||
}
|
||||
token += this->make_inline_table(v);
|
||||
@@ -432,7 +489,7 @@ struct serializer
|
||||
if(!keys_.empty())
|
||||
{
|
||||
token += '[';
|
||||
token += this->serialize_dotted_key(keys_);
|
||||
token += format_keys(keys_);
|
||||
token += "]\n";
|
||||
}
|
||||
token += this->make_multiline_table(v);
|
||||
@@ -441,25 +498,6 @@ struct serializer
|
||||
|
||||
private:
|
||||
|
||||
std::string serialize_key(const toml::key& key) const
|
||||
{
|
||||
return ::toml::format_key(key);
|
||||
}
|
||||
|
||||
std::string serialize_dotted_key(const std::vector<toml::key>& keys) const
|
||||
{
|
||||
std::string token;
|
||||
if(keys.empty()){return token;}
|
||||
|
||||
for(const auto& k : keys)
|
||||
{
|
||||
token += this->serialize_key(k);
|
||||
token += '.';
|
||||
}
|
||||
token.erase(token.size() - 1, 1); // remove trailing `.`
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string escape_basic_string(const std::string& s) const
|
||||
{
|
||||
//XXX assuming `s` is a valid utf-8 sequence.
|
||||
@@ -475,7 +513,19 @@ struct serializer
|
||||
case '\f': {retval += "\\f"; break;}
|
||||
case '\n': {retval += "\\n"; break;}
|
||||
case '\r': {retval += "\\r"; break;}
|
||||
default : {retval += c; break;}
|
||||
default :
|
||||
{
|
||||
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
|
||||
{
|
||||
retval += "\\u00";
|
||||
retval += char(48 + (c / 16));
|
||||
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
retval += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
@@ -489,7 +539,9 @@ struct serializer
|
||||
switch(*i)
|
||||
{
|
||||
case '\\': {retval += "\\\\"; break;}
|
||||
case '\"': {retval += "\\\""; break;}
|
||||
// One or two consecutive "s are allowed.
|
||||
// Later we will check there are no three consecutive "s.
|
||||
// case '\"': {retval += "\\\""; break;}
|
||||
case '\b': {retval += "\\b"; break;}
|
||||
case '\t': {retval += "\\t"; break;}
|
||||
case '\f': {retval += "\\f"; break;}
|
||||
@@ -507,9 +559,40 @@ struct serializer
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {retval += *i; break;}
|
||||
default :
|
||||
{
|
||||
const auto c = *i;
|
||||
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
|
||||
{
|
||||
retval += "\\u00";
|
||||
retval += char(48 + (c / 16));
|
||||
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
retval += c;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -546,8 +629,10 @@ struct serializer
|
||||
for(const auto& item : v)
|
||||
{
|
||||
if(is_first) {is_first = false;} else {token += ',';}
|
||||
token += visit(serializer(std::numeric_limits<std::size_t>::max(),
|
||||
this->float_prec_, true), item);
|
||||
token += visit(serializer(
|
||||
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
|
||||
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
|
||||
/*has_comment*/ !item.comments().empty()), item);
|
||||
}
|
||||
token += ']';
|
||||
return token;
|
||||
@@ -564,10 +649,12 @@ struct serializer
|
||||
{
|
||||
// in inline tables, trailing comma is not allowed (toml-lang #569).
|
||||
if(is_first) {is_first = false;} else {token += ',';}
|
||||
token += this->serialize_key(kv.first);
|
||||
token += format_key(kv.first);
|
||||
token += '=';
|
||||
token += visit(serializer(std::numeric_limits<std::size_t>::max(),
|
||||
this->float_prec_, true), kv.second);
|
||||
token += visit(serializer(
|
||||
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
|
||||
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
|
||||
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||
}
|
||||
token += '}';
|
||||
return token;
|
||||
@@ -577,30 +664,33 @@ struct serializer
|
||||
{
|
||||
std::string token;
|
||||
|
||||
// print non-table stuff first. because after printing [foo.bar], the
|
||||
// remaining non-table values will be assigned into [foo.bar], not [foo]
|
||||
for(const auto kv : v)
|
||||
// print non-table elements first.
|
||||
// ```toml
|
||||
// [foo] # a table we're writing now here
|
||||
// key = "value" # <- non-table element, "key"
|
||||
// # ...
|
||||
// [foo.bar] # <- table element, "bar"
|
||||
// ```
|
||||
// because after printing [foo.bar], the remaining non-table values will
|
||||
// be assigned into [foo.bar], not [foo]. Those values should be printed
|
||||
// earlier.
|
||||
for(const auto& kv : v)
|
||||
{
|
||||
if(kv.second.is_table() || is_array_of_tables(kv.second))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!kv.second.comments().empty() && !no_comment_)
|
||||
{
|
||||
for(const auto& c : kv.second.comments())
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
const auto key_and_sep = this->serialize_key(kv.first) + " = ";
|
||||
token += write_comments(kv.second);
|
||||
|
||||
const auto key_and_sep = format_key(kv.first) + " = ";
|
||||
const auto residual_width = (this->width_ > key_and_sep.size()) ?
|
||||
this->width_ - key_and_sep.size() : 0;
|
||||
token += key_and_sep;
|
||||
token += visit(serializer(residual_width, this->float_prec_, true),
|
||||
kv.second);
|
||||
token += visit(serializer(residual_width, this->float_prec_,
|
||||
/*can be inlined*/ true, /*no comment*/ false, /*keys*/ {},
|
||||
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||
|
||||
if(token.back() != '\n')
|
||||
{
|
||||
token += '\n';
|
||||
@@ -626,45 +716,172 @@ struct serializer
|
||||
ks.push_back(kv.first);
|
||||
|
||||
auto tmp = visit(serializer(this->width_, this->float_prec_,
|
||||
!multiline_table_printed, this->no_comment_, ks),
|
||||
kv.second);
|
||||
!multiline_table_printed, this->no_comment_, ks,
|
||||
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||
|
||||
// If it is the first time to print a multi-line table, it would be
|
||||
// helpful to separate normal key-value pair and subtables by a
|
||||
// newline.
|
||||
// (this checks if the current key-value pair contains newlines.
|
||||
// but it is not perfect because multi-line string can also contain
|
||||
// a newline. in such a case, an empty line will be written) TODO
|
||||
if((!multiline_table_printed) &&
|
||||
std::find(tmp.cbegin(), tmp.cend(), '\n') != tmp.cend())
|
||||
{
|
||||
multiline_table_printed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// still inline tables only.
|
||||
tmp += '\n';
|
||||
}
|
||||
token += '\n'; // separate key-value pairs and subtables
|
||||
|
||||
if(!kv.second.comments().empty() && !no_comment_)
|
||||
{
|
||||
for(const auto& c : kv.second.comments())
|
||||
token += write_comments(kv.second);
|
||||
token += tmp;
|
||||
|
||||
// care about recursive tables (all tables in each level prints
|
||||
// newline and there will be a full of newlines)
|
||||
if(tmp.substr(tmp.size() - 2, 2) != "\n\n" &&
|
||||
tmp.substr(tmp.size() - 4, 4) != "\r\n\r\n" )
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
token += tmp;
|
||||
else
|
||||
{
|
||||
token += write_comments(kv.second);
|
||||
token += tmp;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string make_array_of_tables(const array_type& v) const
|
||||
{
|
||||
// if it's not inlined, we need to add `[[table.key]]`.
|
||||
// but if it can be inlined, we can format it as the following.
|
||||
// ```
|
||||
// table.key = [
|
||||
// {...},
|
||||
// # comment
|
||||
// {...},
|
||||
// ]
|
||||
// ```
|
||||
// This function checks if inlinization is possible or not, and then
|
||||
// format the array-of-tables in a proper way.
|
||||
//
|
||||
// Note about comments:
|
||||
//
|
||||
// If the array itself has a comment (value_has_comment_ == true), we
|
||||
// should try to make it inline.
|
||||
// ```toml
|
||||
// # comment about array
|
||||
// array = [
|
||||
// # comment about table element
|
||||
// {of = "table"}
|
||||
// ]
|
||||
// ```
|
||||
// If it is formatted as a multiline table, the two comments becomes
|
||||
// indistinguishable.
|
||||
// ```toml
|
||||
// # comment about array
|
||||
// # comment about table element
|
||||
// [[array]]
|
||||
// of = "table"
|
||||
// ```
|
||||
// So we need to try to make it inline, and it force-inlines regardless
|
||||
// of the line width limit.
|
||||
// It may fail if the element of a table has comment. In that case,
|
||||
// the array-of-tables will be formatted as a multiline table.
|
||||
if(this->can_be_inlined_ || this->value_has_comment_)
|
||||
{
|
||||
std::string token;
|
||||
if(!keys_.empty())
|
||||
{
|
||||
token += format_key(keys_.back());
|
||||
token += " = ";
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
token += "[\n";
|
||||
for(const auto& item : v)
|
||||
{
|
||||
// if an element of the table has a comment, the table
|
||||
// cannot be inlined.
|
||||
if(this->has_comment_inside(item.as_table()))
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
// write comments for the table itself
|
||||
token += write_comments(item);
|
||||
|
||||
const auto t = this->make_inline_table(item.as_table());
|
||||
|
||||
if(t.size() + 1 > width_ || // +1 for the last comma {...},
|
||||
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
|
||||
{
|
||||
// if the value itself has a comment, ignore the line width limit
|
||||
if( ! this->value_has_comment_)
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
token += t;
|
||||
token += ",\n";
|
||||
}
|
||||
|
||||
if( ! failed)
|
||||
{
|
||||
token += "]\n";
|
||||
return token;
|
||||
}
|
||||
// if failed, serialize them as [[array.of.tables]].
|
||||
}
|
||||
|
||||
std::string token;
|
||||
for(const auto& item : v)
|
||||
{
|
||||
token += write_comments(item);
|
||||
token += "[[";
|
||||
token += format_keys(keys_);
|
||||
token += "]]\n";
|
||||
token += this->make_multiline_table(item.as_table());
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string write_comments(const value_type& v) const
|
||||
{
|
||||
std::string retval;
|
||||
if(this->no_comment_) {return retval;}
|
||||
|
||||
for(const auto& c : v.comments())
|
||||
{
|
||||
retval += '#';
|
||||
retval += c;
|
||||
retval += '\n';
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool is_array_of_tables(const value_type& v) const
|
||||
{
|
||||
if(!v.is_array()) {return false;}
|
||||
const auto& a = v.as_array();
|
||||
return !a.empty() && a.front().is_table();
|
||||
if(!v.is_array() || v.as_array().empty()) {return false;}
|
||||
return is_array_of_tables(v.as_array());
|
||||
}
|
||||
bool is_array_of_tables(const array_type& v) const
|
||||
{
|
||||
// Since TOML v0.5.0, heterogeneous arrays are allowed. So we need to
|
||||
// check all the element in an array to check if the array is an array
|
||||
// of tables.
|
||||
return std::all_of(v.begin(), v.end(), [](const value_type& elem) {
|
||||
return elem.is_table();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool can_be_inlined_;
|
||||
bool no_comment_;
|
||||
bool value_has_comment_;
|
||||
int float_prec_;
|
||||
std::size_t width_;
|
||||
std::vector<toml::key> keys_;
|
||||
@@ -677,6 +894,7 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
||||
int fprec = std::numeric_limits<toml::floating>::max_digits10,
|
||||
bool no_comment = false, bool force_inline = false)
|
||||
{
|
||||
using value_type = basic_value<C, M, V>;
|
||||
// if value is a table, it is considered to be a root object.
|
||||
// the root object can't be an inline table.
|
||||
if(v.is_table())
|
||||
@@ -687,10 +905,11 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
||||
oss << v.comments();
|
||||
oss << '\n'; // to split the file comment from the first element
|
||||
}
|
||||
oss << visit(serializer<C, M, V>(w, fprec, no_comment, false), v);
|
||||
const auto serialized = visit(serializer<value_type>(w, fprec, false, no_comment), v);
|
||||
oss << serialized;
|
||||
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
|
||||
@@ -707,7 +926,7 @@ template<typename charT, typename traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
nocomment(std::basic_ostream<charT, traits>& os)
|
||||
{
|
||||
// by default, it is zero. and by defalut, it shows comments.
|
||||
// by default, it is zero. and by default, it shows comments.
|
||||
os.iword(detail::comment_index(os)) = 1;
|
||||
return os;
|
||||
}
|
||||
@@ -716,7 +935,7 @@ template<typename charT, typename traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
showcomment(std::basic_ostream<charT, traits>& os)
|
||||
{
|
||||
// by default, it is zero. and by defalut, it shows comments.
|
||||
// by default, it is zero. and by default, it shows comments.
|
||||
os.iword(detail::comment_index(os)) = 0;
|
||||
return os;
|
||||
}
|
||||
@@ -726,12 +945,14 @@ template<typename charT, typename traits, typename C,
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
|
||||
{
|
||||
using value_type = basic_value<C, M, V>;
|
||||
|
||||
// get status of std::setw().
|
||||
const auto w = static_cast<std::size_t>(os.width());
|
||||
const int fprec = static_cast<int>(os.precision());
|
||||
os.width(0);
|
||||
|
||||
// by defualt, iword is initialized byl 0. And by default, toml11 outputs
|
||||
// by default, iword is initialized by 0. And by default, toml11 outputs
|
||||
// comments. So `0` means showcomment. 1 means nocommnet.
|
||||
const bool no_comment = (1 == os.iword(detail::comment_index(os)));
|
||||
|
||||
@@ -741,7 +962,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
|
||||
}
|
||||
// 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
|
||||
// put a comment just after a value. in the following way.
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_SOURCE_LOCATION_HPP
|
||||
#define TOML11_SOURCE_LOCATION_HPP
|
||||
#include "region.hpp"
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
|
||||
#include "region.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -38,12 +40,12 @@ struct source_location
|
||||
public:
|
||||
|
||||
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_("")
|
||||
{}
|
||||
|
||||
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_("")
|
||||
{
|
||||
if(reg)
|
||||
@@ -60,6 +62,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(source_location const&) = default;
|
||||
source_location(source_location &&) = default;
|
||||
@@ -82,5 +99,141 @@ struct source_location
|
||||
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(color::should_color() || 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
|
||||
#ifndef TOML11_NO_ERROR_PREFIX
|
||||
<< color::bold << color::red << "[error]" << color::reset
|
||||
#endif
|
||||
<< color::bold << message.substr(7) << color::reset << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
retval
|
||||
#ifndef TOML11_NO_ERROR_PREFIX
|
||||
<< color::bold << color::red << "[error] " << color::reset
|
||||
#endif
|
||||
<< 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
|
||||
#endif// TOML11_SOURCE_LOCATION_HPP
|
||||
|
||||
@@ -16,10 +16,9 @@ struct storage
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
|
||||
storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
|
||||
explicit storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
|
||||
explicit storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
|
||||
~storage() = default;
|
||||
|
||||
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
|
||||
storage& operator=(const storage& rhs)
|
||||
{
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_STRING_HPP
|
||||
#define TOML11_STRING_HPP
|
||||
|
||||
#include "version.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#if __cplusplus >= 201703L
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
#define TOML11_USING_STRING_VIEW 1
|
||||
#include <string_view>
|
||||
#endif
|
||||
#endif
|
||||
@@ -51,7 +57,7 @@ struct string
|
||||
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
|
||||
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
||||
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
||||
string(std::string_view s, string_t k): kind(k), str(s){}
|
||||
|
||||
|
||||
@@ -2,12 +2,19 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_TRAITS_HPP
|
||||
#define TOML11_TRAITS_HPP
|
||||
|
||||
#include "from.hpp"
|
||||
#include "into.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <forward_list>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <chrono>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#if __cplusplus >= 201703L
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
#include <string_view>
|
||||
#endif // has_include(<string_view>)
|
||||
@@ -43,17 +50,23 @@ struct has_mapped_type_impl
|
||||
template<typename T> static std::true_type check(typename T::mapped_type*);
|
||||
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::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
|
||||
{
|
||||
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::true_type check(
|
||||
decltype(std::declval<T>() < std::declval<T>())*);
|
||||
};
|
||||
|
||||
struct has_from_toml_method_impl
|
||||
@@ -76,6 +89,22 @@ struct has_into_toml_method_impl
|
||||
static std::false_type check(...);
|
||||
};
|
||||
|
||||
struct has_specialized_from_impl
|
||||
{
|
||||
template<typename T>
|
||||
static std::false_type check(...);
|
||||
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
|
||||
static std::true_type check(::toml::from<T>*);
|
||||
};
|
||||
struct has_specialized_into_impl
|
||||
{
|
||||
template<typename T>
|
||||
static std::false_type check(...);
|
||||
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
|
||||
static std::true_type check(::toml::from<T>*);
|
||||
};
|
||||
|
||||
|
||||
/// Intel C++ compiler can not use decltype in parent class declaration, here
|
||||
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
|
||||
#ifdef __INTEL_COMPILER
|
||||
@@ -91,7 +120,9 @@ struct has_key_type : decltype(has_key_type_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
|
||||
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>
|
||||
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
|
||||
|
||||
@@ -104,6 +135,11 @@ template<typename T>
|
||||
struct has_into_toml_method
|
||||
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
||||
|
||||
template<typename T>
|
||||
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#undef decltype
|
||||
#endif
|
||||
@@ -111,6 +147,14 @@ struct has_into_toml_method
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++17 and/or/not
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
|
||||
using std::conjunction;
|
||||
using std::disjunction;
|
||||
using std::negation;
|
||||
|
||||
#else
|
||||
|
||||
template<typename ...> struct conjunction : std::true_type{};
|
||||
template<typename T> struct conjunction<T> : T{};
|
||||
template<typename T, typename ... Ts>
|
||||
@@ -128,6 +172,8 @@ struct disjunction<T, Ts...> :
|
||||
template<typename T>
|
||||
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
|
||||
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// type checkers
|
||||
|
||||
@@ -139,6 +185,10 @@ template<typename T> struct is_std_tuple : std::false_type{};
|
||||
template<typename ... Ts>
|
||||
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 Rep, typename Period>
|
||||
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
|
||||
@@ -159,8 +209,10 @@ template<typename T>
|
||||
struct is_container : conjunction<
|
||||
negation<is_map<T>>, // not a map
|
||||
negation<std::is_same<T, std::string>>, // not a std::string
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
negation<std::is_same<T, std::string_view>>, // not a std::string_view
|
||||
#endif // has_include(<string_view>)
|
||||
#endif
|
||||
has_iterator<T>, // has T::iterator
|
||||
has_value_type<T> // has T::value_type
|
||||
@@ -182,6 +234,13 @@ struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++14 index_sequence
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
|
||||
using std::index_sequence;
|
||||
using std::make_index_sequence;
|
||||
|
||||
#else
|
||||
|
||||
template<std::size_t ... Ns> struct index_sequence{};
|
||||
|
||||
template<typename IS, std::size_t N> struct push_back_index_sequence{};
|
||||
@@ -205,15 +264,26 @@ struct index_sequence_maker<0>
|
||||
template<std::size_t N>
|
||||
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
||||
|
||||
#endif // cplusplus >= 2014
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++14 enable_if_t
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
|
||||
using std::enable_if_t;
|
||||
|
||||
#else
|
||||
|
||||
template<bool B, typename T>
|
||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
#endif // cplusplus >= 2014
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// return_type_of_t
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703
|
||||
|
||||
template<typename F, typename ... Args>
|
||||
using return_type_of_t = std::invoke_result_t<F, Args...>;
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_TYPES_HPP
|
||||
#define TOML11_TYPES_HPP
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "comments.hpp"
|
||||
#include "datetime.hpp"
|
||||
#include "string.hpp"
|
||||
#include "traits.hpp"
|
||||
#include "comments.hpp"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -20,9 +21,14 @@ class basic_value;
|
||||
using character = char;
|
||||
using key = std::string;
|
||||
|
||||
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ <= 4
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
using boolean = bool;
|
||||
using integer = std::int64_t;
|
||||
using floating = double; // "float" is a keyward, cannot use it here.
|
||||
using floating = double; // "float" is a keyword, cannot use it here.
|
||||
// the following stuffs are structs defined here, so aliases are not needed.
|
||||
// - string
|
||||
// - offset_datetime
|
||||
@@ -31,12 +37,26 @@ using floating = double; // "float" is a keyward, cannot use it here.
|
||||
// - local_date
|
||||
// - local_time
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// default toml::value and default array/table. these are defined after defining
|
||||
// basic_value itself.
|
||||
// using value = basic_value<discard_comments, std::unordered_map, std::vector>;
|
||||
// using array = typename value::array_type;
|
||||
// using table = typename value::table_type;
|
||||
|
||||
// to avoid warnings about `value_t::integer` is "shadowing" toml::integer in
|
||||
// GCC -Wshadow=global.
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# if 7 <= __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wshadow=global"
|
||||
# else // gcc-6 or older
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
# endif
|
||||
#endif
|
||||
enum class value_t : std::uint8_t
|
||||
{
|
||||
empty = 0,
|
||||
@@ -51,6 +71,9 @@ enum class value_t : std::uint8_t
|
||||
array = 9,
|
||||
table = 10,
|
||||
};
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
template<typename charT, typename traits>
|
||||
inline std::basic_ostream<charT, traits>&
|
||||
@@ -146,4 +169,5 @@ template<typename T, typename V> struct is_exact_toml_type<T const volatile&, V>
|
||||
|
||||
} // detail
|
||||
} // toml
|
||||
|
||||
#endif// TOML11_TYPES_H
|
||||
|
||||
107
toml/utility.hpp
107
toml/utility.hpp
@@ -2,12 +2,14 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_UTILITY_HPP
|
||||
#define TOML11_UTILITY_HPP
|
||||
#include "traits.hpp"
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#include "traits.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#elif defined(__GNUC__)
|
||||
# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
@@ -20,38 +22,41 @@
|
||||
namespace toml
|
||||
{
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
|
||||
using std::make_unique;
|
||||
|
||||
#else
|
||||
|
||||
template<typename T, typename ... Ts>
|
||||
inline std::unique_ptr<T> make_unique(Ts&& ... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
|
||||
}
|
||||
|
||||
#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
inline void resize_impl(T& container, std::size_t N, std::true_type)
|
||||
template<typename Container>
|
||||
void try_reserve_impl(Container& container, std::size_t N, std::true_type)
|
||||
{
|
||||
container.resize(N);
|
||||
return ;
|
||||
container.reserve(N);
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void resize_impl(T& container, std::size_t N, std::false_type)
|
||||
template<typename Container>
|
||||
void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
|
||||
{
|
||||
if(container.size() >= N) {return;}
|
||||
|
||||
throw std::invalid_argument("not resizable type");
|
||||
return;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
template<typename T>
|
||||
inline void resize(T& container, std::size_t N)
|
||||
template<typename Container>
|
||||
void try_reserve(Container& container, std::size_t N)
|
||||
{
|
||||
if(container.size() == N) {return;}
|
||||
|
||||
return detail::resize_impl(container, N, detail::has_resize_method<T>());
|
||||
if(N <= container.size()) {return;}
|
||||
detail::try_reserve_impl(container, N, detail::has_reserve_method<Container>{});
|
||||
return;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -76,14 +81,70 @@ std::string concat_to_string(Ts&& ... args)
|
||||
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
T from_string(const std::string& str, U&& opt)
|
||||
template<typename T>
|
||||
T from_string(const std::string& str, T opt)
|
||||
{
|
||||
T v(static_cast<T>(std::forward<U>(opt)));
|
||||
T v(opt);
|
||||
std::istringstream iss(str);
|
||||
iss >> v;
|
||||
return v;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
template<typename T>
|
||||
decltype(auto) last_one(T&& tail) noexcept
|
||||
{
|
||||
return std::forward<T>(tail);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Ts>
|
||||
decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept
|
||||
{
|
||||
return last_one(std::forward<Ts>(tail)...);
|
||||
}
|
||||
#else // C++11
|
||||
// The following code
|
||||
// ```cpp
|
||||
// 1 | template<typename T, typename ... Ts>
|
||||
// 2 | auto last_one(T&& /*head*/, Ts&& ... tail)
|
||||
// 3 | -> decltype(last_one(std::forward<Ts>(tail)...))
|
||||
// 4 | {
|
||||
// 5 | return last_one(std::forward<Ts>(tail)...);
|
||||
// 6 | }
|
||||
// ```
|
||||
// does not work because the function `last_one(...)` is not yet defined at
|
||||
// line #3, so `decltype()` cannot deduce the type returned from `last_one`.
|
||||
// So we need to determine return type in a different way, like a meta func.
|
||||
|
||||
template<typename T, typename ... Ts>
|
||||
struct last_one_in_pack
|
||||
{
|
||||
using type = typename last_one_in_pack<Ts...>::type;
|
||||
};
|
||||
template<typename T>
|
||||
struct last_one_in_pack<T>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
template<typename ... Ts>
|
||||
using last_one_in_pack_t = typename last_one_in_pack<Ts...>::type;
|
||||
|
||||
template<typename T>
|
||||
T&& last_one(T&& tail) noexcept
|
||||
{
|
||||
return std::forward<T>(tail);
|
||||
}
|
||||
template<typename T, typename ... Ts>
|
||||
enable_if_t<(sizeof...(Ts) > 0), last_one_in_pack_t<Ts&& ...>>
|
||||
last_one(T&& /*head*/, Ts&& ... tail)
|
||||
{
|
||||
return last_one(std::forward<Ts>(tail)...);
|
||||
}
|
||||
|
||||
#endif
|
||||
} // detail
|
||||
|
||||
}// toml
|
||||
#endif // TOML11_UTILITY
|
||||
|
||||
968
toml/value.hpp
968
toml/value.hpp
File diff suppressed because it is too large
Load Diff
42
toml/version.hpp
Normal file
42
toml/version.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef TOML11_VERSION_HPP
|
||||
#define TOML11_VERSION_HPP
|
||||
|
||||
// This file checks C++ version.
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error "__cplusplus is not defined"
|
||||
#endif
|
||||
|
||||
// Since MSVC does not define `__cplusplus` correctly unless you pass
|
||||
// `/Zc:__cplusplus` when compiling, the workaround macros are added.
|
||||
// Those enables you to define version manually or to use MSVC specific
|
||||
// version macro automatically.
|
||||
//
|
||||
// The value of `__cplusplus` macro is defined in the C++ standard spec, but
|
||||
// MSVC ignores the value, maybe because of backward compatibility. Instead,
|
||||
// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in
|
||||
// the C++ standard. First we check the manual version definition, and then
|
||||
// we check if _MSVC_LANG is defined. If neither, use normal `__cplusplus`.
|
||||
//
|
||||
// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170
|
||||
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
|
||||
//
|
||||
#if defined(TOML11_ENFORCE_CXX11)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201103L
|
||||
#elif defined(TOML11_ENFORCE_CXX14)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201402L
|
||||
#elif defined(TOML11_ENFORCE_CXX17)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201703L
|
||||
#elif defined(TOML11_ENFORCE_CXX20)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 202002L
|
||||
#elif defined(_MSVC_LANG) && defined(_MSC_VER) && 1910 <= _MSC_VER
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG
|
||||
#else
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus
|
||||
#endif
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L && _MSC_VER < 1900
|
||||
# error "toml11 requires C++11 or later."
|
||||
#endif
|
||||
|
||||
#endif// TOML11_VERSION_HPP
|
||||
Reference in New Issue
Block a user