Compare commits

...

176 Commits

Author SHA1 Message Date
ToruNiina
1bf9e42835 chore: update version 2019-06-19 21:12:05 +09:00
ToruNiina
4a2c823d56 fix: comparison between values that has a table 2019-06-19 19:32:25 +09:00
ToruNiina
24c28c7f4f fix: correct some SFINAE expressions 2019-06-19 18:59:12 +09:00
ToruNiina
cab3144507 style: format CMakelists.txt 2019-06-19 16:53:45 +09:00
ToruNiina
dee32e7d5e style: make hint messages clearer 2019-06-19 12:58:34 +09:00
ToruNiina
53a185e7a9 fix: revert misjudgement as a bug
Probably I'm too tired.

This reverts commit adcd75e017.
2019-06-18 21:41:30 +09:00
ToruNiina
fd980a8c5d 🔀 Merge branch 'guess-type-error' 2019-06-18 21:29:45 +09:00
ToruNiina
73ac43d70c doc: add contributor 2019-06-18 21:28:50 +09:00
ToruNiina
adcd75e017 fix: correctly initialize offset 2019-06-18 21:27:16 +09:00
Toru Niina
569341a514 Merge pull request #69 from KerstinKeller/cmake_install
Allow to install toml11 library with CMake.
2019-06-17 18:03:00 +09:00
KerstinKeller
0357d8fb57 Add newline to end of CMake files. 2019-06-17 10:04:39 +02:00
ToruNiina
00d40140ac doc: add an example of error message to README 2019-06-17 12:59:29 +09:00
ToruNiina
1bfe8f1f54 Merge branch 'master' into guess-type-error 2019-06-17 12:48:36 +09:00
ToruNiina
bc143263cd Merge branch 'revert-recursive-find' 2019-06-17 11:54:52 +09:00
ToruNiina
1b19d5f1eb doc: update README 2019-06-16 21:44:59 +09:00
ToruNiina
fd7da05798 doc: update README 2019-06-16 20:31:08 +09:00
ToruNiina
cbaaaaca7c revert recursive find function
I found that in a user-code (I'm also one of the users of this library),
this new feature sometimes causes an error. Some of my code won't
compile because of this change. Since toml::table is convertible to
toml::value *implicitly*, if toml::find(table, key, tablename) was
called, the overload resolution becomes ambiguous with toml::find(
value, key1, key2). But dropping support for toml::find(toml::table,
key, tablename) is a breaking change. So I concluded that now is not
the right time yet.
2019-06-16 19:55:40 +09:00
ToruNiina
cf1c9371b6 fix: correct example and positions in err msgs 2019-06-16 17:52:42 +09:00
ToruNiina
62e8d58d8d feat: guess possible format errors 2019-06-16 17:32:29 +09:00
KerstinKeller
acbc2a73cb Allow to install tom11 library with CMake.
Add option to build tests.
2019-06-14 17:24:21 +02:00
ToruNiina
b2daf916b3 doc: add contributor to README 2019-06-11 22:45:46 +09:00
Toru Niina
e66bb3d359 Merge pull request #67 from ToruNiina/hotfix
suppress warnings on clang v7+
2019-06-10 10:54:54 +09:00
Toru Niina
cfaa94f072 Merge pull request #68 from khoitd1997/master
fix sign-compare warning
2019-06-10 10:49:49 +09:00
khoitd1997
2f4f3efbf0 fix sign-compare warning 2019-06-09 12:00:28 -07:00
ToruNiina
06ae67502a fix: move argument correctly 2019-06-09 21:05:46 +09:00
ToruNiina
57cb806e14 Merge branch 'master' into throw-from-as-something 2019-06-08 19:23:32 +09:00
ToruNiina
d6f3654185 refactor: reduce test code by using CHECK_THROW 2019-06-08 19:23:12 +09:00
ToruNiina
8befe3f1ad test: add test for throw/nothrow versions of as_* 2019-06-08 19:20:09 +09:00
ToruNiina
2d43119ac7 doc: change README a bit 2019-06-07 21:05:33 +09:00
ToruNiina
436af12815 doc: update README 2019-06-07 19:43:01 +09:00
ToruNiina
4f4d4380f2 feat: throw from as_* if type differs 2019-06-07 19:34:04 +09:00
ToruNiina
31debcb8aa 🔀 Merge branch 'master' into recursive-find 2019-06-07 19:02:20 +09:00
ToruNiina
2afa0ff0c3 doc: add find(value, key1, key2, ...) to README 2019-06-07 19:01:46 +09:00
ToruNiina
46047c48bf doc: add note about is|as_float to README 2019-06-07 13:40:21 +09:00
ToruNiina
897aecf5d4 test: avoid deprecated functions in the test codes 2019-06-07 13:32:02 +09:00
ToruNiina
7db8388d17 fix: avoid deprecated stuff in the internal code 2019-06-07 13:27:10 +09:00
ToruNiina
62c993e096 feat: add as|is_floating and deprecate as|is_float
to make the function names consistent with snake_case_typenames
2019-06-07 00:10:12 +09:00
ToruNiina
014d882f8f feat: enable to find value by recursive search 2019-06-07 00:06:14 +09:00
ToruNiina
2cbb93d86e fix: #65 Merge branch 'hotfix' 2019-06-03 21:27:25 +09:00
ToruNiina
a19b94511b fix: add space between operator"" and _toml
In C++11, it is required.
2019-06-03 20:58:35 +09:00
ToruNiina
70d0049511 refactor: move some meta-funcs to traits.hpp 2019-06-01 12:35:40 +09:00
ToruNiina
717f5929c2 feat: use detail::none_t instead of char
Although the error value from combinators currently does not have any
information, it can have an information because it is a char value. It
is better to use no-information-type explicitly to make it clear that
it does not have any information. So I added none_t in toml::detai and
use it in combinators and parsers as an error value from combinators.
2019-05-31 17:07:52 +09:00
ToruNiina
81abb6c9d7 perf: remove err-msg from combinator
Generate error message in `parse_something()`, not in `lex_something`.
Since the error message generated by `lex_something` is too difficult to
read for humans, I've disabled the error message generation for the sake
of efficiency (it takes time to generate error message that will never
be read). I think now the error message generation itself safely can be
removed from combinators. At this stage, `lex_something` does not need
to return `result<T, E>` because all the error type would be discarded.
Now it is turned out that returing `optional<T>` from lex_* is enough.
Maybe later I would change the return type itself, but currently I
changed the error type from std::string to char because implementing
optional takes time and effort. It makes the parsing process a bit
faster.
2019-05-30 20:08:37 +09:00
ToruNiina
8bba3c8a14 refactor: use literal instead of empty string
so far, the error value of the lexer is just ignored because they are
not readable (results from all the nested combinator are concatenated,
so they are too redundant). those ones are replaced by a simple literal.
2019-05-30 19:33:25 +09:00
ToruNiina
b13e727b90 refactor: remove unused func, combinator::pattern
because it is not human-readable (too long and redundant)
2019-05-30 18:05:47 +09:00
ToruNiina
d352c9e66f perf: suppress unused error message generation 2019-05-30 17:47:06 +09:00
ToruNiina
c0aaba06d0 Merge branch 'refactoring' 2019-05-30 16:25:10 +09:00
ToruNiina
1633268d57 refactor: use snake_case typename only 2019-05-30 14:39:15 +09:00
ToruNiina
3bf1c2b820 Merge branch 'refactoring' to master 2019-05-30 00:18:07 +09:00
ToruNiina
4dbd2cb9fe refactor: use as_* to avoid needless checking 2019-05-29 21:22:32 +09:00
ToruNiina
65124a8d2e refactor: use is_something instead of is(...)
to reduce the code size a bit
2019-05-29 21:20:22 +09:00
ToruNiina
1b78f161f5 refactor: use is_something/as_something in parser
this reduces the size of the code. And also it skips needless
double-checking, so we can expect it makes parsing a bit faster.
2019-05-29 21:18:17 +09:00
ToruNiina
0ce259ada0 refactor: split throw_bad_cast from value::cast 2019-05-29 21:06:25 +09:00
ToruNiina
74da49f87f refactor: move switch_cast from inside of value
use as_something() instead of it. To realize this, the implementation of
as_something() is also changed. Now as_something does not depends on
`cast`. This reduces complexity around casting toml::value to other types.
2019-05-29 20:18:15 +09:00
ToruNiina
d5d697639c docs: add contributor to README 2019-05-10 23:02:23 +09:00
Toru Niina
0b365ca7d3 Merge pull request #63 from chronoxor/master
Fix Visual Studio 2019 warnings in pedantic compilation mode (/W4 /WX)
2019-05-10 22:58:17 +09:00
Ivan Shynkarenka
db6f3d5d11 Fix Visual Studio 2019 warnings in pedantic compilation mode (/W4 /WX) 2019-05-10 14:58:22 +03:00
ToruNiina
87be890e07 feat: remove deprecated functions 2019-04-28 15:59:09 +09:00
Toru Niina
d72dc706d0 Merge pull request #61 from ToruNiina/as-something
feat: add as_something functions for convenience
2019-04-28 15:02:19 +09:00
ToruNiina
4cbbcd8f62 Merge branch 'master' into as-something 2019-04-27 19:04:44 +09:00
Toru Niina
a2631ecacb Merge pull request #60 from ToruNiina/string-view
support std::string_view
2019-04-27 18:33:59 +09:00
ToruNiina
4bcc5e8375 Merge branch 'master' into as-something 2019-04-27 17:42:12 +09:00
Toru Niina
90f84000ba Merge pull request #59 from ToruNiina/preserve-comments
Preserve comments; related to #48
2019-04-27 17:40:26 +09:00
ToruNiina
20a13754a7 chore: update README for as_* functions 2019-04-27 16:50:44 +09:00
ToruNiina
aa7b9a3965 refactor: rename as_floating -> as_float
Actually, since `floating` is used for toml::types, `as_floating`
seems to be clearer. But currently `is_*` functions uses `float`,
not `floating`, so `as_float` is chosen for the consistency.
In a future release, possibly v3, those names may need to be
re-considered for clarity.
2019-04-27 16:45:25 +09:00
ToruNiina
84ac1d10f3 test: add test for toml::value::as_something 2019-04-27 16:22:50 +09:00
ToruNiina
0d623856a7 feat: add value::as_something() for convenience 2019-04-27 16:22:23 +09:00
ToruNiina
ec0d4e4e8c chore: update README for comments 2019-04-27 15:50:54 +09:00
ToruNiina
80ea736b3f ci: try to update standard library on travis 2019-04-27 14:46:40 +09:00
ToruNiina
ebaa5dfb51 chore: fix build settings for OS X on Travis 2019-04-26 21:10:29 +09:00
ToruNiina
f3bdf083fe fix: fix typo in test code for string_view 2019-04-26 16:51:23 +09:00
ToruNiina
1ce54a9cf9 chore: add auto test with c++17 + latest compilers 2019-04-26 16:35:03 +09:00
ToruNiina
6383a93ce7 chore: check CXX_STANDARD exists or not 2019-04-26 16:33:48 +09:00
ToruNiina
01aa2ef5b2 feat: add ctor to value to init with string_view 2019-04-26 16:33:09 +09:00
ToruNiina
819351f5a4 test: add test for init toml::value by string_view 2019-04-26 16:32:23 +09:00
ToruNiina
2967cebfb3 test: add test to get a toml::value as string_view 2019-04-26 16:31:59 +09:00
ToruNiina
32e9a2c1c7 test: add test for comments in an array 2019-04-26 15:35:41 +09:00
ToruNiina
8e0a40a1aa test: add test for getting comments 2019-04-25 22:34:12 +09:00
ToruNiina
e460826084 feat: enable to get a comment related to a value
- comment_before(): get comments just before a value.
- comment_inline(): get a comment in the same line as a value.
- comment(): get comment_before() + comment_inline().
2019-04-25 22:32:39 +09:00
ToruNiina
aa3445f38c feat: add functions to get comments around region 2019-04-25 22:32:18 +09:00
ToruNiina
408b7bf35e Merge branch 'master' into string-view 2019-04-23 23:32:08 +09:00
ToruNiina
6185dfee14 chore: fix typo in README 2019-04-23 23:31:37 +09:00
ToruNiina
37aa2739a5 chore: add description about string_view to README 2019-04-23 23:27:53 +09:00
ToruNiina
d061c33a16 feat: enable toml::get with std::string_view 2019-04-23 23:24:23 +09:00
ToruNiina
0c7d2d07d4 feat: do not consider string_view as a container
it is a kind of string.
2019-04-23 23:23:57 +09:00
ToruNiina
62cf4373bd feat: conversion toml::string <-> string_view 2019-04-22 23:18:05 +09:00
Toru Niina
a74ad23514 Merge pull request #58 from ToruNiina/improve-err-msg-literal
Improve error message from toml literal
2019-04-22 20:50:11 +09:00
ToruNiina
2d9b4992ec fix: restrict length of underline by size of line
in some cases, `region` contains several lines and `region::size`
returns the whole size that is a sum of lengthes of all the lines.
To avoid too long underlines, restrict the length of underline by
the length of the line that is shown in the message.
2019-04-21 16:38:08 +09:00
ToruNiina
82e8c1e68b fix: skip first ws/newlines in toml literal
when ""_toml literal is used with C++11 raw-string literal,
it normally starts with newline like the following.
```cpp
const auto v = u8R"(
    [table]
    key = "value"
    )"_toml;
```
With this, the error message shows the first empty line that starts just
after `u8R"(` and thus the error message shows nothing. To avoid this,
skip the first empty lines and whitespaces in literal.
2019-04-21 16:31:24 +09:00
ToruNiina
46be054ce9 fix: improve err msg for multiline inline table
show "missing curly brace" instead of "missing table key-value separator"
2019-04-19 13:22:13 +09:00
ToruNiina
789d784769 chore: update README; about literals 2019-04-19 13:18:35 +09:00
ToruNiina
81deb8efde chore: update README 2019-04-19 12:41:24 +09:00
Toru Niina
072dccd05d Merge pull request #56 from ToruNiina/optimization
Optimization
2019-04-19 01:30:29 +09:00
ToruNiina
637c99d637 refactor: generate error message in parser 2019-04-18 15:09:58 +09:00
ToruNiina
0f48852730 perf: check value type before parsing
to avoid needless error message generation
2019-04-18 14:26:27 +09:00
ToruNiina
0499b2907d Merge branch 'master' into optimization 2019-04-18 14:10:08 +09:00
ToruNiina
61e69c9251 fix: count line number from 1, not 0 2019-04-18 13:56:19 +09:00
ToruNiina
4a560ea1e5 fix: show correct error message 2019-04-18 00:04:33 +09:00
ToruNiina
c5b6ee6f81 feat: add yet another constructor to value
to make implementation of parse_value easier
2019-04-17 23:43:42 +09:00
ToruNiina
1a7bf63622 Merge branch 'master' into optimization 2019-04-17 14:58:28 +09:00
Toru Niina
8847cdc0a9 Merge pull request #55 from wbenny/master
fix /W4 warnings on MSVC
2019-04-17 13:16:19 +09:00
ToruNiina
c82e76a111 perf: check string type before parsing it
to avoid unncessary error message generation, check the first some
characters before parsing it. It makes parsing process faster and
is also helpful to generate more accurate error messages.
2019-04-16 21:47:24 +09:00
ToruNiina
4db486d76d perf: check integer prefix before trying to parse
all the parsers generate error messages and error message generation is
not a lightweight task. It concatenates a lot of strings, it formats
many values, etc. To avoid useless error-message generation, first check
which prefix is used and then parse special integers. Additionally, by
checking that, the quality of the error message can be improved (later).
2019-04-16 21:37:12 +09:00
ToruNiina
91966a6917 perf: do not use concat_string if it is not needed
At the earlier stage of the development, I thought that it is useful if
lexer-combinators generate error messages, because by doing this,
parser would not need to generate an error message. But now it turned
out that to show an appropriate error message, parser need to generate
according to the context. And almost all the messages from lexer are
discarded. So I added another parameter to lexer-combinator to suppress
error message generation. In the future, we may want to remove messages
completely from lexers, but currently I will keep it. Removing those
unused message generation makes the parsing process faster.
2019-04-16 21:09:59 +09:00
ToruNiina
b3917aaadf refactor: use snprintf to show char in hex
instead of std::ostringstream.
2019-04-16 20:54:29 +09:00
Petr Benes
ba307003c4 fix /W4 warnings on MSVC 2019-04-16 13:25:45 +02:00
Toru Niina
21fd1271d9 Merge pull request #54 from ToruNiina/hotfix
fix: resolve ambiguity in the `""_toml` literal
2019-04-15 13:34:35 +09:00
ToruNiina
f9ab7d6f56 chore: add note about literals to README.md 2019-04-14 20:08:23 +09:00
ToruNiina
0a3a41a708 test: add test for literals for difficult case 2019-04-14 20:06:11 +09:00
ToruNiina
6c2a536fa5 fix: check literal has a table or an array first
The literal like this `"[[table]]"_toml` caused a syntax error. It is
because the literal parser first check that it might be a bare value
without a key, and parse_array directory throws syntax_error. This
change makes the parser first check a literal is a name of table, and
then parse the content.
2019-04-14 19:48:43 +09:00
Toru Niina
26eced3640 Merge pull request #52 from ToruNiina/speedup-for-large-files
Speedup parsing large files
2019-04-13 16:11:21 +09:00
ToruNiina
6f950c9ec8 perf: cache current line number in location
`location::line_num()` function used to be implemented by using
`std::count`, so each time the parser encounters a type mismatch,
`std::count` was called with almost whole file. It decelerates the
parsing process too much, so I decided to add `line_number_` member
variable to `location` and add `advance/retrace/reset` to `location`
in order to modify the position that is pointed.
2019-04-12 18:32:46 +09:00
ToruNiina
ea13e40889 feat: add static_assert for location/range
to check the container is randomly-accessible
2019-04-12 18:00:53 +09:00
ToruNiina
595fb1aef3 refactor: remove unused function parameter names 2019-04-06 19:39:13 +09:00
ToruNiina
18986978fb chore: add short example code to README 2019-03-24 21:30:27 +09:00
ToruNiina
c3cb22a789 chore: fix example of err msg by re-running sample 2019-03-21 18:12:35 +09:00
ToruNiina
5aebd6b562 fix: restore the back compat of format_error
the following code was okay in the last release
```
toml::format_error("[test]", v, "test", {"hint1", "hint2"})
```
but was not okay in the current master. This commit fixes this.

cons: By this, the number of values to show is limited upto 3.
2019-03-20 20:46:22 +09:00
ToruNiina
4c13085b35 fix: add stream operator for toml::table 2019-03-20 19:30:08 +09:00
ToruNiina
8709e8a14e chore: fix incorrect syntax highlight in README 2019-03-20 19:29:03 +09:00
ToruNiina
9eea46ec01 chore: fix typoes and broken links in README 2019-03-20 12:06:55 +09:00
ToruNiina
2e9f937c43 chore: update README 2019-03-20 11:53:03 +09:00
Toru Niina
65b10b6537 Merge pull request #46 from ToruNiina/toml-literal
feat: add ""_toml literal
2019-03-20 10:12:56 +09:00
ToruNiina
b51a8d5966 fix: add missing include file in test code 2019-03-20 00:58:58 +09:00
Toru Niina
55e3d70869 Merge pull request #47 from ToruNiina/format-table
`toml::format` and top-level table
2019-03-20 00:49:59 +09:00
ToruNiina
20ba57e389 fix: add missing const specifier to some of get()s 2019-03-20 00:37:13 +09:00
ToruNiina
39bc3c64fe test: add test for ""_toml literals 2019-03-20 00:36:46 +09:00
ToruNiina
40ccf1d912 feat: add argument to control top-level inlinization 2019-03-19 23:25:26 +09:00
ToruNiina
982ae36428 feat: add ""_toml literal 2019-03-19 21:34:57 +09:00
ToruNiina
d6714ec450 feat: detect value type and format as a file
in toml::format
2019-03-19 21:24:51 +09:00
ToruNiina
773c3816be ci: remove needless confirmation on CI 2019-03-19 19:39:45 +09:00
Toru Niina
1b417ddc7a Merge pull request #45 from ToruNiina/get_or
fix `get_or` and add `find_or`
2019-03-19 01:41:21 +09:00
ToruNiina
7a0ecf977d feat: add find_or(table, key, fallback)
get_or(value, fallback) is still ok, but get_or(table, key, fallback)
is now deprecated.
2019-03-18 17:44:03 +09:00
ToruNiina
aade704411 refactor: remove needless overload of get_or 2019-03-18 17:10:18 +09:00
ToruNiina
ca3f6102ef fix: correctly resolve overloads of get_or 2019-03-18 16:44:36 +09:00
ToruNiina
4a58b629ce feat: add a way to check arg is "string literal" 2019-03-18 16:31:12 +09:00
ToruNiina
3adba237b8 feat: enable to show message for deprecated() 2019-03-18 16:28:27 +09:00
Toru Niina
ccf03d9291 Merge pull request #44 from ToruNiina/test-link
test: add test for multiple translation unit
2019-03-18 15:20:04 +09:00
Toru Niina
30ae90ebd5 Merge pull request #43 from ToruNiina/hotfix
fix: incorrect move in constructor and return type deducing in toml::visit
2019-03-18 14:08:23 +09:00
ToruNiina
d5369c3429 test: add test for multiple translation unit 2019-03-18 12:39:58 +09:00
Toru Niina
48f2f0555d Merge pull request #42 from ToruNiina/test-suite
run toml-test suite
2019-03-18 12:33:48 +09:00
ToruNiina
f40fd12e25 refactor: add and rewrite comments 2019-03-18 11:09:12 +09:00
ToruNiina
65c2c3c238 fix: correctly deduce return value of visitor 2019-03-18 10:53:04 +09:00
ToruNiina
891a61a5e3 fix: do not move array element without checking 2019-03-18 02:05:55 +09:00
ToruNiina
1e6f30f6fa chore: update README.md 2019-03-18 01:50:23 +09:00
ToruNiina
02346a3126 Merge branch 'master' into test-suite 2019-03-18 01:40:17 +09:00
Toru Niina
1908f18e95 Merge pull request #41 from ToruNiina/hotfix
fix: simplify and correct the format of timezone
2019-03-18 01:39:11 +09:00
ToruNiina
3bfa7f09ba test: use the test suite in the effective way
add tests/check_toml_test.cpp to compare json object
2019-03-18 01:36:43 +09:00
ToruNiina
243f43fafd Merge branch 'master' into hotfix 2019-03-17 21:16:37 +09:00
ToruNiina
66e27a94b6 fix: simplify and correct the format of timezone 2019-03-17 21:14:17 +09:00
ToruNiina
227688ec63 ci: make result clearer a bit 2019-03-17 19:36:23 +09:00
ToruNiina
e761a503c0 ci: fix silly mistake in circleci script 2019-03-17 19:27:58 +09:00
ToruNiina
209ad79a8f ci: fix config file of circleci 2019-03-17 19:26:22 +09:00
ToruNiina
cdf209d7f6 ci: show the status on CI 2019-03-17 19:23:52 +09:00
ToruNiina
77ab391885 ci: fix name of directory and add test script 2019-03-17 19:20:24 +09:00
ToruNiina
6628fe5ace test: add language agnostic toml-test 2019-03-17 19:12:13 +09:00
Toru Niina
f3e3000d45 Merge pull request #40 from ToruNiina/remove-to-toml
refactor: remove to_toml and related tests
2019-03-17 13:12:30 +09:00
Toru Niina
f7380c6e32 Merge pull request #39 from ToruNiina/throw-incorrect-unicode
Throw syntax_error when parser encounter an incorrect utf-8 codepoint
2019-03-17 13:12:16 +09:00
Toru Niina
d86870e038 Merge pull request #38 from ToruNiina/get-any-type
extended conversions
2019-03-17 13:11:59 +09:00
Toru Niina
0908806915 Merge pull request #33 from ToruNiina/is-something
add `is_boolean` and other stuffs like that
2019-03-16 23:55:01 +09:00
ToruNiina
d17c192681 refactor: remove to_toml and related tests 2019-03-16 17:05:58 +09:00
ToruNiina
cad8f51256 doc: add explanation of conversions to README 2019-03-16 16:56:37 +09:00
ToruNiina
43014c6619 fix: remove redefined default template argument 2019-03-16 16:24:10 +09:00
ToruNiina
30a41aa710 fix: use older style in BOOST_TEST 2019-03-16 16:15:01 +09:00
ToruNiina
04bfeba3f2 merge branch master into get-any-type 2019-03-16 15:58:18 +09:00
ToruNiina
190636b791 fix: support getting a container of external types 2019-03-16 15:52:22 +09:00
ToruNiina
31e450f9af test: add test for from/into based conversions 2019-03-16 15:46:21 +09:00
ToruNiina
b1b72a94a8 feat: support conversion with external types 2019-03-16 14:44:04 +09:00
ToruNiina
6929bcdf78 feat: add from<T> and into<T> 2019-03-16 14:27:05 +09:00
ToruNiina
fd063af7ce refactor: make include guard style uniform 2019-03-16 14:19:47 +09:00
ToruNiina
df6dcbc4ed feat: check a class has from/into_toml member fn
to support better serialization
2019-03-16 14:16:31 +09:00
ToruNiina
76863cb27f refactor: simplify branches about utf8 codepoint 2019-03-15 17:48:47 +09:00
ToruNiina
514df99e40 feat: consider invalid UTF-8 as syntax_error
the following codepoints are considered to be a syntax_error
- [0xD800, 0xDFFF]
- larger than 0x10FFFF
2019-03-15 17:39:31 +09:00
ToruNiina
055353a460 chore: merge branch 'master' into is-something 2019-03-15 17:25:17 +09:00
ToruNiina
c4c416e8b2 doc: add is_* function to README 2019-03-12 22:18:25 +09:00
ToruNiina
6693ec78f4 test: add test for toml::value::is_something() 2019-03-12 20:44:27 +09:00
ToruNiina
dc112bd6c1 feat: add is_[boolean|integer|...]() member func
it is an alias to is<toml::value_t::[Boolean|Integer|...]>
2019-03-12 20:43:07 +09:00
38 changed files with 3853 additions and 1040 deletions

59
.circleci/config.yml Normal file
View File

@@ -0,0 +1,59 @@
version: 2.1
jobs:
test_suite:
environment:
- GOPATH: /home/circleci/go
docker:
- image: circleci/golang:1.9
steps:
- checkout
- run:
command: |
g++ --version
cd tests/
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test
go get github.com/BurntSushi/toml-test
$GOPATH/bin/toml-test ./check_toml_test
output_result:
docker:
- image: circleci/buildpack-deps:bionic
steps:
- checkout
- run:
command: |
g++ --version
cd tests/
g++ -std=c++11 -O2 -Wall -Wextra -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
cd toml-test/tests/invalid
for f in $(ls ./*.toml);
do echo "==> ${f}";
cat ${f};
echo "---------------------------------------";
./check ${f} invalid;
if [ $? -ne 0 ] ; then
exit 1
fi
echo "=======================================";
done
cd ../valid
for f in $(ls ./*.toml);
do echo "==> ${f}";
cat ${f};
echo "---------------------------------------";
./check ${f} valid;
if [ $? -ne 0 ] ; then
exit 1
fi
echo "=======================================";
done
workflows:
version: 2.1
test:
jobs:
- test_suite
- output_result

View File

@@ -5,7 +5,7 @@ matrix:
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-5"
env: COMPILER="g++-5" CXX_STANDARD=11
addons:
apt:
sources:
@@ -16,7 +16,7 @@ matrix:
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-6"
env: COMPILER="g++-6" CXX_STANDARD=11
addons:
apt:
sources:
@@ -27,7 +27,7 @@ matrix:
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-7"
env: COMPILER="g++-7" CXX_STANDARD=11
addons:
apt:
sources:
@@ -38,7 +38,18 @@ matrix:
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8"
env: COMPILER="g++-8" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
- libboost-all-dev
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=17
addons:
apt:
sources:
@@ -49,7 +60,7 @@ matrix:
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-3.7"
env: COMPILER="clang++-3.7" CXX_STANDARD=11
addons:
apt:
sources:
@@ -61,7 +72,7 @@ matrix:
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-4.0"
env: COMPILER="clang++-4.0" CXX_STANDARD=11
addons:
apt:
sources:
@@ -73,7 +84,7 @@ matrix:
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-5.0"
env: COMPILER="clang++-5.0" CXX_STANDARD=11
addons:
apt:
sources:
@@ -85,7 +96,7 @@ matrix:
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-6.0"
env: COMPILER="clang++-6.0" CXX_STANDARD=11
addons:
apt:
sources:
@@ -97,7 +108,7 @@ matrix:
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-7"
env: COMPILER="clang++-7" CXX_STANDARD=11
addons:
apt:
sources:
@@ -109,7 +120,7 @@ matrix:
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8"
env: COMPILER="clang++-8" CXX_STANDARD=11
addons:
apt:
sources:
@@ -118,14 +129,38 @@ matrix:
packages:
- clang-8
- libboost-all-dev
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=17
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
packages:
- clang-8
- g++-8
- libboost-all-dev
- os: osx
language: cpp
compiler: clang
env: CXX_STANDARD=11
script:
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
mkdir -p cmake
travis_retry wget "https://cmake.org/files/v3.11/cmake-3.11.2-Linux-x86_64.tar.gz"
tar xf cmake-3.11.2-Linux-x86_64.tar.gz -C cmake --strip-components=1
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
else
brew upgrade cmake
fi
- cmake --version
- mkdir build
- cd build
- git clone https://github.com/toml-lang/toml.git
- cmake -DCMAKE_CXX_COMPILER=$COMPILER ..
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD ..
- make
- ctest --output-on-failure

View File

@@ -1,10 +1,23 @@
cmake_minimum_required(VERSION 2.8)
enable_testing()
project(toml11)
set(toml11_VERSION_MAYOR 2)
set(toml11_VERSION_MINOR 4)
set(toml11_VERSION_PATCH 0)
set(toml11_VERSION
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
)
option(toml11_BUILD_TEST "Build toml tests" ON)
include(CheckCXXCompilerFlag)
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
set(CMAKE_CXX_STANDARD 11)
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.
@@ -31,5 +44,62 @@ else()
endif()
endif()
include_directories(${PROJECT_SOURCE_DIR})
add_subdirectory(tests)
# Set some common directories
include(GNUInstallDirs)
set(toml11_install_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/toml11)
set(toml11_install_include_dir ${CMAKE_INSTALL_INCLUDEDIR})
set(toml11_config_dir ${CMAKE_CURRENT_BINARY_DIR}/cmake/)
set(toml11_config ${toml11_config_dir}/toml11Config.cmake)
set(toml11_config_version ${toml11_config_dir}/toml11ConfigVersion.cmake)
add_library(toml11 INTERFACE)
target_include_directories(toml11 INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${toml11_install_include_dir}>
)
add_library(toml11::toml11 ALIAS toml11)
# Write config and version config files
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${toml11_config_version}
VERSION ${toml11_VERSION}
COMPATIBILITY SameMajorVersion
)
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 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::
)
if (toml11_BUILD_TEST)
add_subdirectory(tests)
endif ()

822
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
@PACKAGE_INIT@
include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake")

View File

@@ -20,15 +20,17 @@ set(TEST_NAMES
test_parse_inline_table
test_parse_key
test_parse_table_key
test_literals
test_comments
test_get
test_get_related_func
test_to_toml
test_from_toml
test_parse_file
test_serialize_file
test_parse_unicode
test_error_detection
test_format_error
test_extended_conversions
)
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
@@ -86,7 +88,7 @@ add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
foreach(TEST_NAME ${TEST_NAMES})
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
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})
@@ -98,3 +100,9 @@ foreach(TEST_NAME ${TEST_NAMES})
)
endif()
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)

41
tests/check.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "toml.hpp"
#include <iostream>
#include <iomanip>
int main(int argc, char **argv)
{
if(argc != 3)
{
std::cerr << "usage: ./check [filename] [valid|invalid]" << std::endl;
return 1;
}
const std::string file_kind(argv[2]);
try
{
const auto data = toml::parse(argv[1]);
std::cout << std::setprecision(16) << std::setw(80) << data;
if(file_kind == "valid")
{
return 0;
}
else
{
return 1;
}
}
catch(const toml::syntax_error& err)
{
std::cout << "what(): " << err.what() << std::endl;
if(file_kind == "invalid")
{
return 0;
}
else
{
return 1;
}
}
return 127;
}

142
tests/check_toml_test.cpp Normal file
View File

@@ -0,0 +1,142 @@
#include "toml.hpp"
#include <iostream>
#include <iomanip>
struct json_serializer
{
void operator()(toml::boolean v)
{
std::cout << "{\"type\":\"bool\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(toml::integer v)
{
std::cout << "{\"type\":\"integer\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(toml::floating v)
{
std::cout << "{\"type\":\"float\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::string& v)
{
// 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) << "\"}";
return ;
}
void operator()(const toml::local_time& v)
{
std::cout << "{\"type\":\"local_time\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::local_date& v)
{
std::cout << "{\"type\":\"local_date\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::local_datetime& v)
{
std::cout << "{\"type\":\"local_datetime\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::offset_datetime& v)
{
std::cout << "{\"type\":\"datetime\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::array& v)
{
if(!v.empty() && v.front().is_table())
{
std::cout << '[';
bool is_first = true;
for(const auto& elem : v)
{
if(!is_first) {std::cout << ", ";}
is_first = false;
toml::visit(*this, elem);
}
std::cout << ']';
}
else
{
std::cout << "{\"type\":\"array\",\"value\":[";
bool is_first = true;
for(const auto& elem : v)
{
if(!is_first) {std::cout << ", ";}
is_first = false;
toml::visit(*this, elem);
}
std::cout << "]}";
}
return ;
}
void operator()(const toml::table& v)
{
std::cout << '{';
bool is_first = true;
for(const auto& elem : v)
{
if(!is_first) {std::cout << ", ";}
is_first = false;
std::cout << toml::format(toml::string(elem.first),
std::numeric_limits<std::size_t>::max());
std::cout << ':';
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()
{
try
{
std::vector<char> buf;
std::cin.peek();
while(!std::cin.eof())
{
buf.push_back(std::cin.get());
std::cin.peek();
}
std::string bufstr(buf.begin(), buf.end());
std::istringstream ss(bufstr);
const auto data = toml::parse(ss);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10);
toml::visit(json_serializer(), data);
return 0;
}
catch(const toml::syntax_error& err)
{
std::cout << "what(): " << err.what() << std::endl;
return 1;
}
}

125
tests/test_comments.cpp Normal file
View File

@@ -0,0 +1,125 @@
#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>
BOOST_AUTO_TEST_CASE(test_comment_before)
{
using namespace toml::literals::toml_literals;
{
const toml::value v = u8R"(
# comment for a.
a = 42
# comment for b.
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), u8"# comment for a.");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), u8"# comment for b.");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), "");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), "");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8"# comment for a.");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8"# comment for b.");
}
{
const toml::value v = u8R"(
# comment for a.
# another comment for a.
a = 42
# comment for b.
# also comment for b.
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), u8R"(# comment for a.
# another comment for a.)");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), u8R"(# comment for b.
# also comment for b.)");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), u8"");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), u8"");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8R"(# comment for a.
# another comment for a.)");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8R"(# comment for b.
# also comment for b.)");
}
}
BOOST_AUTO_TEST_CASE(test_comment_inline)
{
using namespace toml::literals::toml_literals;
{
const toml::value v = u8R"(
a = 42 # comment for a.
b = "baz" # comment for b.
)"_toml;
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), "");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), "");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), u8"# comment for a.");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), u8"# comment for b.");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8"# comment for a.");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8"# comment for b.");
}
{
const toml::value v = u8R"(
a = [ # comment for a.
42,
] # this also.
b = [ # comment for b.
"bar",
]
c = [
3.14, # this is not a comment for c, but 3.14.
] # comment for c.
)"_toml;
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), "");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), "");
BOOST_CHECK_EQUAL(toml::find(v, "c").comment_before(), "");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), u8R"(# comment for a.
# this also.)");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), u8"# comment for b.");
BOOST_CHECK_EQUAL(toml::find(v, "c").comment_inline(), u8"# comment for c.");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8R"(# comment for a.
# this also.)");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8"# comment for b.");
BOOST_CHECK_EQUAL(toml::find(v, "c").comment(), u8"# comment for c.");
const auto& c0 = toml::find<toml::array>(v, "c").at(0);
BOOST_CHECK_EQUAL(c0.comment(), u8"# this is not a comment for c, but 3.14.");
}
}
BOOST_AUTO_TEST_CASE(test_comment_both)
{
using namespace toml::literals::toml_literals;
{
const toml::value v = u8R"(
# comment for a.
a = 42 # inline comment for a.
# comment for b.
b = "baz" # inline comment for b.
)"_toml;
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_before(), "# comment for a.");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_before(), "# comment for b.");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment_inline(), "# inline comment for a.");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment_inline(), "# inline comment for b.");
BOOST_CHECK_EQUAL(toml::find(v, "a").comment(), u8R"(# comment for a.
# inline comment for a.)");
BOOST_CHECK_EQUAL(toml::find(v, "b").comment(), u8R"(# comment for b.
# inline comment for b.)");
}
}

View File

@@ -0,0 +1,116 @@
#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>
namespace extlib
{
struct foo
{
int a;
std::string b;
};
struct bar
{
int a;
std::string b;
void from_toml(const toml::value& v)
{
this->a = toml::find<int>(v, "a");
this->b = toml::find<std::string>(v, "b");
return ;
}
toml::table into_toml() const
{
return toml::table{{"a", this->a}, {"b", this->b}};
}
};
} // extlib
namespace toml
{
template<>
struct from<extlib::foo>
{
static extlib::foo from_toml(const toml::value& v)
{
return extlib::foo{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
}
};
template<>
struct into<extlib::foo>
{
static toml::table into_toml(const extlib::foo& f)
{
return toml::table{{"a", f.a}, {"b", f.b}};
}
};
} // toml
BOOST_AUTO_TEST_CASE(test_conversion_by_member_methods)
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto foo = toml::get<extlib::foo>(v);
BOOST_CHECK_EQUAL(foo.a, 42);
BOOST_CHECK_EQUAL(foo.b, "baz");
const toml::value v2(foo);
BOOST_CHECK_EQUAL(v, v2);
}
BOOST_AUTO_TEST_CASE(test_conversion_by_specialization)
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto bar = toml::get<extlib::bar>(v);
BOOST_CHECK_EQUAL(bar.a, 42);
BOOST_CHECK_EQUAL(bar.b, "baz");
const toml::value v2(bar);
BOOST_CHECK_EQUAL(v, v2);
}
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
{
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 foos = toml::get<std::vector<extlib::foo>>(v);
BOOST_CHECK_EQUAL(foos.size() , 4ul);
BOOST_CHECK_EQUAL(foos.at(0).a , 42);
BOOST_CHECK_EQUAL(foos.at(1).a , 43);
BOOST_CHECK_EQUAL(foos.at(2).a , 44);
BOOST_CHECK_EQUAL(foos.at(3).a , 45);
BOOST_CHECK_EQUAL(foos.at(0).b , "baz");
BOOST_CHECK_EQUAL(foos.at(1).b , "qux");
BOOST_CHECK_EQUAL(foos.at(2).b , "quux");
BOOST_CHECK_EQUAL(foos.at(3).b , "foobar");
const auto bars = toml::get<std::vector<extlib::bar>>(v);
BOOST_CHECK_EQUAL(bars.size() , 4ul);
BOOST_CHECK_EQUAL(bars.at(0).a , 42);
BOOST_CHECK_EQUAL(bars.at(1).a , 43);
BOOST_CHECK_EQUAL(bars.at(2).a , 44);
BOOST_CHECK_EQUAL(bars.at(3).a , 45);
BOOST_CHECK_EQUAL(bars.at(0).b , "baz");
BOOST_CHECK_EQUAL(bars.at(1).b , "qux");
BOOST_CHECK_EQUAL(bars.at(2).b , "quux");
BOOST_CHECK_EQUAL(bars.at(3).b , "foobar");
}

View File

@@ -22,7 +22,7 @@ BOOST_AUTO_TEST_CASE(test_1_value)
{
const std::string pretty_error =
toml::format_error("[error] test error", val, "this is a value",
std::vector<std::string>{"this is a hint"});
{"this is a hint"});
std::cout << pretty_error << std::endl;
}
}
@@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(test_2_values)
toml::format_error("[error] test error with two values",
v1, "this is the answer",
v2, "this is the pi",
std::vector<std::string>{"hint"});
{"hint"});
std::cout << pretty_error << std::endl;
}
}
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(test_3_values)
v1, "this is the answer",
v2, "this is the pi",
v3, "this is a meta-syntactic variable",
std::vector<std::string>{"hint 1", "hint 2"});
{"hint 1", "hint 2"});
std::cout << pretty_error << std::endl;
}
}

View File

@@ -12,6 +12,9 @@
#include <list>
#include <deque>
#include <array>
#if __cplusplus >= 201703L
#include <string_view>
#endif
BOOST_AUTO_TEST_CASE(test_get_exact)
@@ -166,6 +169,17 @@ BOOST_AUTO_TEST_CASE(test_get_string_type)
toml::get<std::string>(v) += "bar";
BOOST_CHECK_EQUAL("foobar", toml::get<std::string>(v));
}
#if __cplusplus >= 201703L
{
toml::value v("foo", toml::string_t::basic);
BOOST_CHECK_EQUAL("foo", toml::get<std::string_view>(v));
}
{
toml::value v("foo", toml::string_t::literal);
BOOST_CHECK_EQUAL("foo", toml::get<std::string_view>(v));
}
#endif
}
BOOST_AUTO_TEST_CASE(test_get_toml_array)

View File

@@ -45,21 +45,194 @@ BOOST_AUTO_TEST_CASE(test_find)
BOOST_AUTO_TEST_CASE(test_get_or)
{
{
toml::table v{{"num", 42}};
BOOST_CHECK_EQUAL(42, toml::get_or<int>(v, "num", 0));
BOOST_CHECK_EQUAL(0, toml::get_or<int>(v, "foo", 0));
}
{
toml::value v = toml::table{{"num", 42}};
BOOST_CHECK_EQUAL(42, toml::get_or<int>(v, "num", 0));
BOOST_CHECK_EQUAL(0, toml::get_or<int>(v, "foo", 0));
}
// requires conversion int -> uint
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_CHECK_EQUAL(42, toml::get_or<int>(v1, 0));
BOOST_CHECK_EQUAL(0, toml::get_or<int>(v2, 0));
BOOST_CHECK_EQUAL(42u, toml::get_or(v1, 0u));
BOOST_CHECK_EQUAL(0u, toml::get_or(v2, 0u));
}
// exact toml type
{
toml::value v1(42);
toml::value v2(3.14);
toml::integer opt(0);
BOOST_CHECK_EQUAL(42, toml::get_or(v1, opt));
BOOST_CHECK_EQUAL(0, toml::get_or(v2, opt));
toml::value v3("foobar");
toml::string s("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::get_or(v3, s));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v1, s));
}
// std::string
{
toml::value v1("foobar");
toml::value v2(42);
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s1));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s1));
std::string& v1r = toml::get_or(v1, s1);
std::string& s1r = toml::get_or(v2, s1);
BOOST_CHECK_EQUAL("foobar", v1r);
BOOST_CHECK_EQUAL("bazqux", s1r);
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s2));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s2));
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, std::move(s1)));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, std::move(s1)));
}
// string literal
{
toml::value v1("foobar");
toml::value v2(42);
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, "bazqux"));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, "bazqux"));
const char* lit = "bazqux";
BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, lit));
BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, lit));
}
}
BOOST_AUTO_TEST_CASE(test_find_or)
{
// ========================================================================
// pass toml::value
//
// requires conversion int -> uint
{
toml::table v{{"num", 42}};
BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u));
BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u));
}
// exact toml type
{
toml::table v1{{"key", 42 }};
toml::table v2{{"key", 3.14}};
toml::table v3{{"not", "key"}};
toml::integer opt(0);
BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", opt));
BOOST_CHECK_EQUAL(0, toml::find_or(v2, "key", opt));
BOOST_CHECK_EQUAL(0, toml::find_or(v3, "key", opt));
toml::table v4{{"str", "foobar"}};
toml::string s("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s));
}
// std::string
{
toml::table v1{{"key", "foobar"}};
toml::table v2{{"key", 42}};
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1));
std::string& v1r = toml::find_or(v1, "key", s1);
std::string& s1r = toml::find_or(v2, "key", s1);
BOOST_CHECK_EQUAL("foobar", v1r);
BOOST_CHECK_EQUAL("bazqux", s1r);
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2));
BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1)));
s1 = "bazqux"; // restoring moved value
BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1)));
}
// string literal
{
toml::table v1{{"key", "foobar"}};
toml::table v2{{"key",42}};
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux"));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux"));
const char* lit = "bazqux";
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit));
}
// ========================================================================
// pass toml::value
//
// requires conversion int -> uint
{
toml::table v = toml::table{{"num", 42}};
BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u));
BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u));
}
// exact toml type
{
toml::value v1 = toml::table{{"key", 42 }};
toml::value v2 = toml::table{{"key", 3.14}};
toml::value v3 = toml::table{{"not", "key"}};
BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", toml::integer(0)));
BOOST_CHECK_EQUAL( 0, toml::find_or(v2, "key", toml::integer(0)));
BOOST_CHECK_EQUAL( 0, toml::find_or(v3, "key", toml::integer(0)));
toml::value v4 = toml::table{{"str", "foobar"}};
toml::string s("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s));
}
// std::string
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key", 42}};
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1));
std::string& v1r = toml::find_or(v1, "key", s1);
std::string& s1r = toml::find_or(v2, "key", s1);
BOOST_CHECK_EQUAL("foobar", v1r);
BOOST_CHECK_EQUAL("bazqux", s1r);
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2));
BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1)));
s1 = "bazqux"; // restoring moved value
BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1)));
}
// string literal
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key",42}};
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux"));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux"));
const char* lit = "bazqux";
BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit));
BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit));
}
}

View File

@@ -18,7 +18,7 @@ do { \
BOOST_CHECK_EQUAL(static_cast<std::size_t>(std::distance( \
loc.begin(), loc.iter())), region.size()); \
} else { \
std::cerr << "lexer " << lxr::pattern() << " failed with input `"; \
std::cerr << "lexer failed with input `"; \
std::cerr << token << "`. expected `" << expected << "`\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
} \

154
tests/test_literals.cpp Normal file
View File

@@ -0,0 +1,154 @@
#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 <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 = u8R"(
a = 42
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(r, v);
}
{
const toml::value r{
{"c", 3.14},
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = u8R"(
c = 3.14
[table]
a = 42
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(r, v);
}
{
const toml::value r{
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = u8R"(
[table]
a = 42
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(r, v);
}
}
BOOST_AUTO_TEST_CASE(test_value_as_literal)
{
using namespace toml::literals::toml_literals;
{
const toml::value v1 = u8"true"_toml;
const toml::value v2 = u8"false"_toml;
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK(v2.is_boolean());
BOOST_CHECK(toml::get<bool>(v1));
BOOST_CHECK(!toml::get<bool>(v2));
}
{
const toml::value v1 = u8"123_456"_toml;
const toml::value v2 = u8"0b0010"_toml;
const toml::value v3 = u8"0xDEADBEEF"_toml;
BOOST_CHECK(v1.is_integer());
BOOST_CHECK(v2.is_integer());
BOOST_CHECK(v3.is_integer());
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v1), 123456);
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v2), 2);
BOOST_CHECK_EQUAL(toml::get<toml::integer>(v3), 0xDEADBEEF);
}
{
const toml::value v1 = u8"3.1415"_toml;
const toml::value v2 = u8"6.02e+23"_toml;
BOOST_CHECK(v1.is_floating());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_CLOSE(toml::get<double>(v1), 3.1415, 0.00001);
BOOST_CHECK_CLOSE(toml::get<double>(v2), 6.02e23, 0.0001);
}
{
const toml::value v1 = u8R"("foo")"_toml;
const toml::value v2 = u8R"('foo')"_toml;
const toml::value v3 = u8R"("""foo""")"_toml;
const toml::value v4 = u8R"('''foo''')"_toml;
BOOST_CHECK(v1.is_string());
BOOST_CHECK(v2.is_string());
BOOST_CHECK(v3.is_string());
BOOST_CHECK(v4.is_string());
BOOST_CHECK_EQUAL(toml::get<std::string>(v1), "foo");
BOOST_CHECK_EQUAL(toml::get<std::string>(v2), "foo");
BOOST_CHECK_EQUAL(toml::get<std::string>(v3), "foo");
BOOST_CHECK_EQUAL(toml::get<std::string>(v4), "foo");
}
{
const toml::value v1 = u8R"([1,2,3])"_toml;
BOOST_CHECK(v1.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3}));
const toml::value v2 = u8R"([1,])"_toml;
BOOST_CHECK(v2.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(v2) == std::vector<int>{1}));
const toml::value v3 = u8R"([[1,]])"_toml;
BOOST_CHECK(v3.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(toml::get<toml::array>(v3).front()) == std::vector<int>{1}));
const toml::value v4 = u8R"([[1],])"_toml;
BOOST_CHECK(v4.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(toml::get<toml::array>(v4).front()) == std::vector<int>{1}));
}
{
const toml::value v1 = u8R"({a = 42})"_toml;
BOOST_CHECK(v1.is_table());
BOOST_CHECK((toml::get<std::map<std::string,int>>(v1) ==
std::map<std::string,int>{{"a", 42}}));
}
{
const toml::value v1 = u8"1979-05-27"_toml;
BOOST_CHECK(v1.is_local_date());
BOOST_CHECK_EQUAL(toml::get<toml::local_date>(v1),
toml::local_date(1979, toml::month_t::May, 27));
}
{
const toml::value v1 = u8"12:00:00"_toml;
BOOST_CHECK(v1.is_local_time());
BOOST_CHECK(toml::get<std::chrono::hours>(v1) == std::chrono::hours(12));
}
{
const toml::value v1 = u8"1979-05-27T07:32:00"_toml;
BOOST_CHECK(v1.is_local_datetime());
BOOST_CHECK_EQUAL(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_CHECK(v1.is_offset_datetime());
BOOST_CHECK_EQUAL(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)));
}
}

View File

@@ -0,0 +1,11 @@
#include <toml.hpp>
int read_a(const toml::table&);
int main()
{
const std::string content("a = 0");
std::istringstream iss(content);
const auto data = toml::parse(iss, "test_multiple_translation_unit.toml");
return read_a(data);
}

View File

@@ -0,0 +1,6 @@
#include <toml.hpp>
int read_a(const toml::table& t)
{
return toml::get<int>(t.at("a"));
}

View File

@@ -1,189 +0,0 @@
#define BOOST_TEST_MODULE "test_to_toml"
#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 <list>
BOOST_AUTO_TEST_CASE(test_value_boolean)
{
toml::value v1 = toml::to_toml(true);
toml::value v2 = toml::to_toml(false);
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean);
BOOST_CHECK(v1.is(toml::value_t::Boolean));
BOOST_CHECK(v2.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v2.is<toml::Boolean>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
}
BOOST_AUTO_TEST_CASE(test_value_integer)
{
toml::value v1 = toml::to_toml(-42);
toml::value v2 = toml::to_toml(42u);
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Integer);
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Integer);
BOOST_CHECK(v1.is(toml::value_t::Integer));
BOOST_CHECK(v2.is(toml::value_t::Integer));
BOOST_CHECK(v1.is<toml::Integer>());
BOOST_CHECK(v2.is<toml::Integer>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
}
BOOST_AUTO_TEST_CASE(test_value_float)
{
toml::value v1 = toml::to_toml(3.14);
toml::value v2 = toml::to_toml(3.14f);
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Float);
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float);
BOOST_CHECK(v1.is(toml::value_t::Float));
BOOST_CHECK(v2.is(toml::value_t::Float));
BOOST_CHECK(v1.is<toml::Float>());
BOOST_CHECK(v2.is<toml::Float>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
}
BOOST_AUTO_TEST_CASE(test_value_string)
{
toml::value v1 = toml::to_toml(std::string("foo"));
toml::value v2 = toml::to_toml(std::string("foo"), toml::string_t::literal);
toml::value v3 = toml::to_toml("foo");
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::String);
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::String);
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::String);
BOOST_CHECK(v1.is(toml::value_t::String));
BOOST_CHECK(v2.is(toml::value_t::String));
BOOST_CHECK(v3.is(toml::value_t::String));
BOOST_CHECK(v1.is<toml::String>());
BOOST_CHECK(v2.is<toml::String>());
BOOST_CHECK(v3.is<toml::String>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "foo");
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "foo");
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::String>(), "foo");
}
BOOST_AUTO_TEST_CASE(test_value_local_date)
{
toml::value v1 = toml::to_toml(toml::local_date(2018, toml::month_t::Jan, 31));
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
BOOST_CHECK(v1.is<toml::LocalDate>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
toml::local_date(2018, toml::month_t::Jan, 31));
}
BOOST_AUTO_TEST_CASE(test_value_local_time)
{
toml::value v1 = toml::to_toml(toml::local_time(12, 30, 45));
toml::value v2 = toml::to_toml(std::chrono::hours(12) + std::chrono::minutes(30) +
std::chrono::seconds(45));
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime);
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalTime);
BOOST_CHECK(v1.is(toml::value_t::LocalTime));
BOOST_CHECK(v2.is(toml::value_t::LocalTime));
BOOST_CHECK(v1.is<toml::LocalTime>());
BOOST_CHECK(v2.is<toml::LocalTime>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
toml::local_time(12, 30, 45));
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalTime>(),
toml::local_time(12, 30, 45));
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
v2.cast<toml::value_t::LocalTime>());
}
BOOST_AUTO_TEST_CASE(test_value_local_datetime)
{
toml::value v1 = toml::to_toml(toml::local_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45)
));
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
BOOST_CHECK(v1.is<toml::LocalDatetime>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45)));
}
BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
{
toml::value v1 = toml::to_toml(toml::offset_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45),
toml::time_offset(9, 0)
));
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45),
toml::time_offset(9, 0)
));
}
BOOST_AUTO_TEST_CASE(test_value_array)
{
std::vector<int> v{1,2,3,4,5};
toml::value v1 = toml::to_toml(v);
toml::value v2 = toml::to_toml(6,7,8,9,0);
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
BOOST_CHECK(v1.is(toml::value_t::Array));
BOOST_CHECK(v1.is<toml::Array>());
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
BOOST_CHECK(v2.is(toml::value_t::Array));
BOOST_CHECK(v2.is<toml::Array>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 3);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 4);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 5);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 8);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 9);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 0);
}
BOOST_AUTO_TEST_CASE(test_value_table)
{
toml::value v1 = toml::to_toml({{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}});
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
BOOST_CHECK(v1.is(toml::value_t::Table));
BOOST_CHECK(v1.is<toml::Table>());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Integer>(), 42);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "qux");
}

View File

@@ -9,6 +9,11 @@
#include <map>
#include <list>
#if __cplusplus >= 201703L
#include <string_view>
#endif
BOOST_AUTO_TEST_CASE(test_value_boolean)
{
toml::value v1(true);
@@ -20,9 +25,15 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
BOOST_CHECK(v2.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v2.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK(v2.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
BOOST_CHECK_EQUAL(v2.as_boolean(), false);
BOOST_CHECK_EQUAL(v1.as_boolean(std::nothrow), true);
BOOST_CHECK_EQUAL(v2.as_boolean(std::nothrow), false);
v1 = false;
v2 = true;
@@ -33,9 +44,13 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
BOOST_CHECK(v2.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v2.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK(v2.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), false);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), false);
BOOST_CHECK_EQUAL(v2.as_boolean(), true);
toml::value v3(v1);
toml::value v4(v2);
@@ -48,9 +63,13 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
BOOST_CHECK(v4.is(toml::value_t::Boolean));
BOOST_CHECK(v3.is<toml::Boolean>());
BOOST_CHECK(v4.is<toml::Boolean>());
BOOST_CHECK(v3.is_boolean());
BOOST_CHECK(v4.is_boolean());
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Boolean>(), false);
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v3.as_boolean(), false);
BOOST_CHECK_EQUAL(v4.as_boolean(), true);
toml::value v5(std::move(v1));
toml::value v6(std::move(v2));
@@ -61,9 +80,13 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
BOOST_CHECK(v6.is(toml::value_t::Boolean));
BOOST_CHECK(v5.is<toml::Boolean>());
BOOST_CHECK(v6.is<toml::Boolean>());
BOOST_CHECK(v3.is_boolean());
BOOST_CHECK(v4.is_boolean());
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Boolean>(), false);
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v5.as_boolean(), false);
BOOST_CHECK_EQUAL(v6.as_boolean(), true);
v1 = 42;
v2 = 3.14;
@@ -74,9 +97,13 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
BOOST_CHECK(v2.is(toml::value_t::Float));
BOOST_CHECK(v1.is<toml::Integer>());
BOOST_CHECK(v2.is<toml::Float>());
BOOST_CHECK(v1.is_integer());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 42);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_EQUAL(v1.as_integer(), 42);
BOOST_CHECK_EQUAL(v2.as_floating(), 3.14);
}
BOOST_AUTO_TEST_CASE(test_value_integer)
@@ -90,9 +117,15 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
BOOST_CHECK(v2.is(toml::value_t::Integer));
BOOST_CHECK(v1.is<toml::Integer>());
BOOST_CHECK(v2.is<toml::Integer>());
BOOST_CHECK(v1.is_integer());
BOOST_CHECK(v2.is_integer());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
BOOST_CHECK_EQUAL(v1.as_integer(), -42);
BOOST_CHECK_EQUAL(v2.as_integer(), 42u);
BOOST_CHECK_EQUAL(v1.as_integer(std::nothrow), -42);
BOOST_CHECK_EQUAL(v2.as_integer(std::nothrow), 42u);
v1 = 54;
v2 = -54;
@@ -103,9 +136,13 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
BOOST_CHECK(v2.is(toml::value_t::Integer));
BOOST_CHECK(v1.is<toml::Integer>());
BOOST_CHECK(v2.is<toml::Integer>());
BOOST_CHECK(v1.is_integer());
BOOST_CHECK(v2.is_integer());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 54);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), -54);
BOOST_CHECK_EQUAL(v1.as_integer(), 54);
BOOST_CHECK_EQUAL(v2.as_integer(), -54);
toml::value v3(v1);
toml::value v4(v2);
@@ -118,9 +155,13 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
BOOST_CHECK(v4.is(toml::value_t::Integer));
BOOST_CHECK(v3.is<toml::Integer>());
BOOST_CHECK(v4.is<toml::Integer>());
BOOST_CHECK(v3.is_integer());
BOOST_CHECK(v4.is_integer());
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Integer>(), 54);
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Integer>(), -54);
BOOST_CHECK_EQUAL(v3.as_integer(), 54);
BOOST_CHECK_EQUAL(v4.as_integer(), -54);
toml::value v5(std::move(v1));
toml::value v6(std::move(v2));
@@ -131,9 +172,13 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
BOOST_CHECK(v6.is(toml::value_t::Integer));
BOOST_CHECK(v5.is<toml::Integer>());
BOOST_CHECK(v6.is<toml::Integer>());
BOOST_CHECK(v5.is_integer());
BOOST_CHECK(v6.is_integer());
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Integer>(), 54);
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Integer>(), -54);
BOOST_CHECK_EQUAL(v5.as_integer(), 54);
BOOST_CHECK_EQUAL(v6.as_integer(), -54);
v1 = true;
v2 = false;
@@ -144,9 +189,13 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
BOOST_CHECK(v2.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v2.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK(v2.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
BOOST_CHECK_EQUAL(v2.as_boolean(), false);
}
BOOST_AUTO_TEST_CASE(test_value_float)
@@ -160,9 +209,15 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v2.is(toml::value_t::Float));
BOOST_CHECK(v1.is<toml::Float>());
BOOST_CHECK(v2.is<toml::Float>());
BOOST_CHECK(v1.is_floating());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_EQUAL (v1.cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
BOOST_CHECK_EQUAL (v1.as_floating(), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(), 3.14, 1e-2);
BOOST_CHECK_EQUAL (v1.as_floating(std::nothrow), 3.14);
BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(std::nothrow), 3.14, 1e-2);
v1 = 2.718f;
v2 = 2.718;
@@ -173,9 +228,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v2.is(toml::value_t::Float));
BOOST_CHECK(v1.is<toml::Float>());
BOOST_CHECK(v2.is<toml::Float>());
BOOST_CHECK(v1.is_floating());
BOOST_CHECK(v2.is_floating());
BOOST_CHECK_CLOSE_FRACTION(v1.cast<toml::value_t::Float>(), 2.718, 1e-3);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_EQUAL (v2.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v1.as_floating(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v2.as_floating(), 2.718);
toml::value v3(v1);
toml::value v4(v2);
@@ -188,9 +247,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v4.is(toml::value_t::Float));
BOOST_CHECK(v3.is<toml::Float>());
BOOST_CHECK(v4.is<toml::Float>());
BOOST_CHECK(v3.is_floating());
BOOST_CHECK(v4.is_floating());
BOOST_CHECK_CLOSE_FRACTION(v3.cast<toml::value_t::Float>(), 2.718, 1e-3);
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_EQUAL (v4.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v3.as_floating(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v4.as_floating(), 2.718);
toml::value v5(std::move(v1));
toml::value v6(std::move(v2));
@@ -201,9 +264,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v6.is(toml::value_t::Float));
BOOST_CHECK(v5.is<toml::Float>());
BOOST_CHECK(v6.is<toml::Float>());
BOOST_CHECK(v5.is_floating());
BOOST_CHECK(v6.is_floating());
BOOST_CHECK_CLOSE_FRACTION(v5.cast<toml::value_t::Float>(), 2.718, 1e-3);
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_EQUAL (v6.cast<toml::value_t::Float>(), 2.718);
BOOST_CHECK_CLOSE_FRACTION(v5.as_floating(), 2.718, 1e-3);
BOOST_CHECK_EQUAL (v6.as_floating(), 2.718);
v1 = true;
v2 = false;
@@ -214,9 +281,13 @@ BOOST_AUTO_TEST_CASE(test_value_float)
BOOST_CHECK(v2.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v2.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK(v2.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
BOOST_CHECK_EQUAL(v2.as_boolean(), false);
}
BOOST_AUTO_TEST_CASE(test_value_string)
@@ -234,10 +305,19 @@ BOOST_AUTO_TEST_CASE(test_value_string)
BOOST_CHECK(v1.is<toml::String>());
BOOST_CHECK(v2.is<toml::String>());
BOOST_CHECK(v3.is<toml::String>());
BOOST_CHECK(v1.is_string());
BOOST_CHECK(v2.is_string());
BOOST_CHECK(v3.is_string());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "foo");
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "foo");
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::String>(), "foo");
BOOST_CHECK_EQUAL(v1.as_string(), "foo");
BOOST_CHECK_EQUAL(v2.as_string(), "foo");
BOOST_CHECK_EQUAL(v3.as_string(), "foo");
BOOST_CHECK_EQUAL(v1.as_string(std::nothrow), "foo");
BOOST_CHECK_EQUAL(v2.as_string(std::nothrow), "foo");
BOOST_CHECK_EQUAL(v3.as_string(std::nothrow), "foo");
v1 = "bar";
v2 = "bar";
@@ -249,13 +329,17 @@ BOOST_AUTO_TEST_CASE(test_value_string)
BOOST_CHECK(v1.is(toml::value_t::String));
BOOST_CHECK(v2.is(toml::value_t::String));
BOOST_CHECK(v3.is(toml::value_t::String));
BOOST_CHECK(v1.is<toml::String>());
BOOST_CHECK(v2.is<toml::String>());
BOOST_CHECK(v3.is<toml::String>());
BOOST_CHECK(v1.is_string());
BOOST_CHECK(v2.is_string());
BOOST_CHECK(v3.is_string());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "bar");
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "bar");
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::String>(), "bar");
BOOST_CHECK_EQUAL(v1.as_string(), "bar");
BOOST_CHECK_EQUAL(v2.as_string(), "bar");
BOOST_CHECK_EQUAL(v3.as_string(), "bar");
toml::value v4(v1);
toml::value v5(v2);
@@ -273,10 +357,17 @@ BOOST_AUTO_TEST_CASE(test_value_string)
BOOST_CHECK(v4.is<toml::String>());
BOOST_CHECK(v5.is<toml::String>());
BOOST_CHECK(v6.is<toml::String>());
BOOST_CHECK(v4.is_string());
BOOST_CHECK(v5.is_string());
BOOST_CHECK(v6.is_string());
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "bar");
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "bar");
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::String>(), "bar");
BOOST_CHECK_EQUAL(v4.as_string(), "bar");
BOOST_CHECK_EQUAL(v5.as_string(), "bar");
BOOST_CHECK_EQUAL(v6.as_string(), "bar");
v4.cast<toml::value_t::String>().str.at(2) = 'z';
v5.cast<toml::value_t::String>().str.at(2) = 'z';
@@ -291,10 +382,13 @@ BOOST_AUTO_TEST_CASE(test_value_string)
BOOST_CHECK(v4.is<toml::String>());
BOOST_CHECK(v5.is<toml::String>());
BOOST_CHECK(v6.is<toml::String>());
BOOST_CHECK(v4.is_string());
BOOST_CHECK(v5.is_string());
BOOST_CHECK(v6.is_string());
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "baz");
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "baz");
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::String>(), "baz");
BOOST_CHECK_EQUAL(v4.as_string(), "baz");
BOOST_CHECK_EQUAL(v5.as_string(), "baz");
BOOST_CHECK_EQUAL(v6.as_string(), "baz");
v1 = true;
v2 = true;
@@ -309,10 +403,35 @@ BOOST_AUTO_TEST_CASE(test_value_string)
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v2.is<toml::Boolean>());
BOOST_CHECK(v3.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK(v2.is_boolean());
BOOST_CHECK(v3.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
BOOST_CHECK_EQUAL(v2.as_boolean(), true);
BOOST_CHECK_EQUAL(v3.as_boolean(), true);
#if __cplusplus >= 201703L
std::string_view sv = "foo";
toml::value v7(sv);
toml::value v8(sv, toml::string_t::literal);
BOOST_CHECK_EQUAL(v7.type(), toml::value_t::String);
BOOST_CHECK_EQUAL(v8.type(), toml::value_t::String);
BOOST_CHECK(v7.is(toml::value_t::String));
BOOST_CHECK(v8.is(toml::value_t::String));
BOOST_CHECK(v7.is<toml::String>());
BOOST_CHECK(v8.is<toml::String>());
BOOST_CHECK(v7.is_string());
BOOST_CHECK(v8.is_string());
BOOST_CHECK_EQUAL(v7.cast<toml::value_t::String>(), "foo");
BOOST_CHECK_EQUAL(v8.cast<toml::value_t::String>(), "foo");
#endif
}
BOOST_AUTO_TEST_CASE(test_value_local_date)
@@ -322,18 +441,26 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
BOOST_CHECK(v1.is<toml::LocalDate>());
BOOST_CHECK(v1.is_local_date());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
toml::local_date(2018, toml::month_t::Jan, 31));
BOOST_CHECK_EQUAL(v1.as_local_date(),
toml::local_date(2018, toml::month_t::Jan, 31));
BOOST_CHECK_EQUAL(v1.as_local_date(std::nothrow),
toml::local_date(2018, toml::month_t::Jan, 31));
v1 = toml::local_date(2018, toml::month_t::Apr, 1);
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
BOOST_CHECK(v1.is<toml::LocalDate>());
BOOST_CHECK(v1.is_local_date());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
toml::local_date(2018, toml::month_t::Apr, 1));
BOOST_CHECK_EQUAL(v1.as_local_date(),
toml::local_date(2018, toml::month_t::Apr, 1));
toml::value v2(v1);
BOOST_CHECK(v2 == v1);
@@ -341,15 +468,20 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDate);
BOOST_CHECK(v2.is(toml::value_t::LocalDate));
BOOST_CHECK(v2.is<toml::LocalDate>());
BOOST_CHECK(v2.is_local_date());
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDate>(),
toml::local_date(2018, toml::month_t::Apr, 1));
BOOST_CHECK_EQUAL(v2.as_local_date(),
toml::local_date(2018, toml::month_t::Apr, 1));
v1 = true;
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
BOOST_CHECK(v1.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
}
BOOST_AUTO_TEST_CASE(test_value_local_time)
@@ -364,21 +496,36 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
BOOST_CHECK(v2.is(toml::value_t::LocalTime));
BOOST_CHECK(v1.is<toml::LocalTime>());
BOOST_CHECK(v2.is<toml::LocalTime>());
BOOST_CHECK(v1.is_local_time());
BOOST_CHECK(v2.is_local_time());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
toml::local_time(12, 30, 45));
BOOST_CHECK_EQUAL(v1.as_local_time(),
toml::local_time(12, 30, 45));
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalTime>(),
toml::local_time(12, 30, 45));
BOOST_CHECK_EQUAL(v2.as_local_time(),
toml::local_time(12, 30, 45));
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
v2.cast<toml::value_t::LocalTime>());
BOOST_CHECK_EQUAL(v1.as_local_time(),
v2.as_local_time());
BOOST_CHECK_EQUAL(v1.as_local_time(std::nothrow),
v2.as_local_time(std::nothrow));
v1 = toml::local_time(1, 30, 0, /*ms*/ 100, /*us*/ 0);
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime);
BOOST_CHECK(v1.is(toml::value_t::LocalTime));
BOOST_CHECK(v1.is<toml::LocalTime>());
BOOST_CHECK(v1.is_local_time());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
toml::local_time(1, 30, 0, 100, 0));
BOOST_CHECK_EQUAL(v1.as_local_time(),
toml::local_time(1, 30, 0, 100, 0));
toml::value v3(v1);
BOOST_CHECK(v3 == v1);
@@ -386,15 +533,20 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::LocalTime);
BOOST_CHECK(v3.is(toml::value_t::LocalTime));
BOOST_CHECK(v3.is<toml::LocalTime>());
BOOST_CHECK(v3.is_local_time());
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::LocalTime>(),
toml::local_time(1, 30, 0, 100, 0));
BOOST_CHECK_EQUAL(v3.as_local_time(),
toml::local_time(1, 30, 0, 100, 0));
v1 = true;
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
BOOST_CHECK(v1.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
}
BOOST_AUTO_TEST_CASE(test_value_local_datetime)
@@ -407,11 +559,21 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
BOOST_CHECK(v1.is<toml::LocalDatetime>());
BOOST_CHECK(v1.is_local_datetime());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45)));
BOOST_CHECK_EQUAL(v1.as_local_datetime(),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45)));
BOOST_CHECK_EQUAL(v1.as_local_datetime(std::nothrow),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45)));
v1 = toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
@@ -420,11 +582,16 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
BOOST_CHECK(v1.is<toml::LocalDatetime>());
BOOST_CHECK(v1.is_local_datetime());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30)));
BOOST_CHECK_EQUAL(v1.as_local_datetime(),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30)));
toml::value v2(v1);
BOOST_CHECK(v2 == v1);
@@ -432,17 +599,25 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDatetime);
BOOST_CHECK(v2.is(toml::value_t::LocalDatetime));
BOOST_CHECK(v2.is<toml::LocalDatetime>());
BOOST_CHECK(v2.is_local_datetime());
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDatetime>(),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30)));
BOOST_CHECK_EQUAL(v2.as_local_datetime(),
toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30)));
v1 = true;
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
BOOST_CHECK(v1.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
}
BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
@@ -456,6 +631,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
BOOST_CHECK(v1.is_offset_datetime());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
toml::offset_datetime(
@@ -463,6 +639,19 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
toml::local_time(12, 30, 45),
toml::time_offset(9, 0)
));
BOOST_CHECK_EQUAL(v1.as_offset_datetime(),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45),
toml::time_offset(9, 0)
));
BOOST_CHECK_EQUAL(v1.as_offset_datetime(std::nothrow),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Jan, 31),
toml::local_time(12, 30, 45),
toml::time_offset(9, 0)
));
v1 = toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
@@ -472,12 +661,19 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
BOOST_CHECK(v1.is_offset_datetime());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30),
toml::time_offset(9, 0)));
BOOST_CHECK_EQUAL(v1.as_offset_datetime(),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30),
toml::time_offset(9, 0)));
toml::value v2(v1);
BOOST_CHECK(v2 == v1);
@@ -485,17 +681,26 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::OffsetDatetime);
BOOST_CHECK(v2.is(toml::value_t::OffsetDatetime));
BOOST_CHECK(v2.is<toml::OffsetDatetime>());
BOOST_CHECK(v2.is_offset_datetime());
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::OffsetDatetime>(),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30),
toml::time_offset(9, 0)));
BOOST_CHECK_EQUAL(v2.as_offset_datetime(),
toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 1),
toml::local_time(1, 15, 30),
toml::time_offset(9, 0)));
v1 = true;
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
BOOST_CHECK(v1.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
}
BOOST_AUTO_TEST_CASE(test_value_array)
@@ -507,16 +712,28 @@ BOOST_AUTO_TEST_CASE(test_value_array)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
BOOST_CHECK(v1.is(toml::value_t::Array));
BOOST_CHECK(v1.is<toml::Array>());
BOOST_CHECK(v1.is_array());
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
BOOST_CHECK(v2.is(toml::value_t::Array));
BOOST_CHECK(v2.is<toml::Array>());
BOOST_CHECK(v2.is_array());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 3);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 4);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 5);
BOOST_CHECK_EQUAL(v1.as_array().at(0).as_integer(), 1);
BOOST_CHECK_EQUAL(v1.as_array().at(1).as_integer(), 2);
BOOST_CHECK_EQUAL(v1.as_array().at(2).as_integer(), 3);
BOOST_CHECK_EQUAL(v1.as_array().at(3).as_integer(), 4);
BOOST_CHECK_EQUAL(v1.as_array().at(4).as_integer(), 5);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(0).as_integer(), 1);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(1).as_integer(), 2);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(2).as_integer(), 3);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(3).as_integer(), 4);
BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(4).as_integer(), 5);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
@@ -530,22 +747,36 @@ BOOST_AUTO_TEST_CASE(test_value_array)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
BOOST_CHECK(v1.is(toml::value_t::Array));
BOOST_CHECK(v1.is<toml::Array>());
BOOST_CHECK(v1.is_array());
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
BOOST_CHECK(v2.is(toml::value_t::Array));
BOOST_CHECK(v2.is<toml::Array>());
BOOST_CHECK(v2.is_array());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 8);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 9);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 0);
BOOST_CHECK_EQUAL(v1.as_array().at(0).as_integer(), 6);
BOOST_CHECK_EQUAL(v1.as_array().at(1).as_integer(), 7);
BOOST_CHECK_EQUAL(v1.as_array().at(2).as_integer(), 8);
BOOST_CHECK_EQUAL(v1.as_array().at(3).as_integer(), 9);
BOOST_CHECK_EQUAL(v1.as_array().at(4).as_integer(), 0);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 3);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 4);
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 5);
BOOST_CHECK_EQUAL(v2.as_array().at(0).as_integer(), 1);
BOOST_CHECK_EQUAL(v2.as_array().at(1).as_integer(), 2);
BOOST_CHECK_EQUAL(v2.as_array().at(2).as_integer(), 3);
BOOST_CHECK_EQUAL(v2.as_array().at(3).as_integer(), 4);
BOOST_CHECK_EQUAL(v2.as_array().at(4).as_integer(), 5);
toml::value v3(v1);
BOOST_CHECK(v3 == v1);
@@ -553,18 +784,27 @@ BOOST_AUTO_TEST_CASE(test_value_array)
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Array);
BOOST_CHECK(v3.is(toml::value_t::Array));
BOOST_CHECK(v3.is<toml::Array>());
BOOST_CHECK(v3.is_array());
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 8);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 9);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 0);
BOOST_CHECK_EQUAL(v3.as_array().at(0).as_integer(), 6);
BOOST_CHECK_EQUAL(v3.as_array().at(1).as_integer(), 7);
BOOST_CHECK_EQUAL(v3.as_array().at(2).as_integer(), 8);
BOOST_CHECK_EQUAL(v3.as_array().at(3).as_integer(), 9);
BOOST_CHECK_EQUAL(v3.as_array().at(4).as_integer(), 0);
v1 = true;
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
BOOST_CHECK(v1.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
}
BOOST_AUTO_TEST_CASE(test_value_table)
@@ -574,20 +814,33 @@ BOOST_AUTO_TEST_CASE(test_value_table)
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
BOOST_CHECK(v1.is(toml::value_t::Table));
BOOST_CHECK(v1.is<toml::Table>());
BOOST_CHECK(v1.is_table());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Integer>(), 42);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "qux");
BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_integer(), 42);
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_floating(), 3.14);
BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "qux");
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("foo").as_integer(), 42);
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("bar").as_floating(), 3.14);
BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("baz").as_string().str, "qux");
v1 = toml::table{{"foo", 2.71}, {"bar", 54}, {"baz", "quux"}};
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
BOOST_CHECK(v1.is(toml::value_t::Table));
BOOST_CHECK(v1.is<toml::Table>());
BOOST_CHECK(v1.is_table());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "quux");
BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_floating(), 2.71);
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_integer(), 54);
BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "quux");
toml::value v3(v1);
BOOST_CHECK(v3 == v1);
@@ -595,14 +848,39 @@ BOOST_AUTO_TEST_CASE(test_value_table)
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Table);
BOOST_CHECK(v3.is(toml::value_t::Table));
BOOST_CHECK(v3.is<toml::Table>());
BOOST_CHECK(v3.is_table());
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "quux");
BOOST_CHECK_EQUAL(v3.as_table().at("foo").as_floating(), 2.71);
BOOST_CHECK_EQUAL(v3.as_table().at("bar").as_integer(), 54);
BOOST_CHECK_EQUAL(v3.as_table().at("baz").as_string().str, "quux");
v1 = true;
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
BOOST_CHECK(v1.is(toml::value_t::Boolean));
BOOST_CHECK(v1.is<toml::Boolean>());
BOOST_CHECK(v1.is_boolean());
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
BOOST_CHECK_EQUAL(v1.as_boolean(), true);
}
BOOST_AUTO_TEST_CASE(test_value_empty)
{
toml::value v1;
BOOST_CHECK(v1.is_uninitialized());
BOOST_CHECK(v1.is(toml::value_t::Empty));
BOOST_CHECK_THROW(v1.as_boolean(), toml::type_error);
BOOST_CHECK_THROW(v1.as_integer(), toml::type_error);
BOOST_CHECK_THROW(v1.as_floating(), toml::type_error);
BOOST_CHECK_THROW(v1.as_string(), toml::type_error);
BOOST_CHECK_THROW(v1.as_offset_datetime(), toml::type_error);
BOOST_CHECK_THROW(v1.as_local_datetime(), toml::type_error);
BOOST_CHECK_THROW(v1.as_local_date(), toml::type_error);
BOOST_CHECK_THROW(v1.as_local_time(), toml::type_error);
BOOST_CHECK_THROW(v1.as_array(), toml::type_error);
BOOST_CHECK_THROW(v1.as_table(), toml::type_error);
}

View File

@@ -34,8 +34,8 @@
#endif
#include "toml/parser.hpp"
#include "toml/literal.hpp"
#include "toml/serializer.hpp"
#include "toml/to_toml.hpp"
#include "toml/from_toml.hpp"
#include "toml/get.hpp"

View File

@@ -9,7 +9,10 @@
#include <type_traits>
#include <iterator>
#include <limits>
#include <array>
#include <iomanip>
#include <cstdio>
#include <cassert>
#include <cctype>
// they scans characters and returns region if it matches to the condition.
@@ -38,10 +41,12 @@ inline std::string show_char(const char c)
}
else
{
std::ostringstream oss;
oss << "0x" << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(c);
return oss.str();
std::array<char, 5> buf;
buf.fill('\0');
const auto r = std::snprintf(
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
assert(r == static_cast<int>(buf.size()) - 1);
return std::string(buf.data());
}
}
@@ -51,26 +56,24 @@ struct character
static constexpr char target = C;
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
const char c = *(loc.iter());
if(c != target)
{
return err(concat_to_string("expected '", show_char(target),
"' but got '", show_char(c), "'."));
return none();
}
++(loc.iter()); // update location
loc.advance(); // update location
return ok(region<Cont>(loc, first, loc.iter()));
}
static std::string pattern() {return show_char(target);}
};
template<char C>
constexpr char character<C>::target;
@@ -86,30 +89,24 @@ struct in_range
static constexpr char lower = Low;
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
const char c = *(loc.iter());
if(c < lower || upper < c)
{
return err(concat_to_string("expected character in range "
"[", show_char(lower), ", ", show_char(upper), "] but got ",
"'", show_char(c), "'."));
return none();
}
++(loc.iter());
loc.advance();
return ok(region<Cont>(loc, first, loc.iter()));
}
static std::string pattern()
{
return concat_to_string("[",show_char(lower),"-",show_char(upper),"]");
}
};
template<char L, char U> constexpr char in_range<L, U>::upper;
template<char L, char U> constexpr char in_range<L, U>::lower;
@@ -120,30 +117,24 @@ template<typename Combinator>
struct exclude
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
if(loc.iter() == loc.end()) {return none();}
auto first = loc.iter();
auto rslt = Combinator::invoke(loc);
if(rslt.is_ok())
{
loc.iter() = first; // rollback
return err(concat_to_string(
"invalid pattern (", Combinator::pattern(), ") appeared ",
rslt.unwrap().str()));
loc.reset(first);
return none();
}
loc.iter() = std::next(first);
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
return ok(region<Cont>(loc, first, loc.iter()));
}
static std::string pattern()
{
return concat_to_string("^(", Combinator::pattern(), ')');
}
};
// increment `iter`, if matches. otherwise, just return empty string.
@@ -151,7 +142,8 @@ template<typename Combinator>
struct maybe
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
@@ -163,11 +155,6 @@ struct maybe
}
return ok(region<Cont>(loc));
}
static std::string pattern()
{
return concat_to_string('(', Combinator::pattern(), ")?");
}
};
template<typename ... Ts>
@@ -177,7 +164,8 @@ template<typename Head, typename ... Tail>
struct sequence<Head, Tail...>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
@@ -186,31 +174,26 @@ struct sequence<Head, Tail...>
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
}
// called from the above function only, recursively.
template<typename Cont, typename Iterator>
static result<region<Cont>, std::string>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
reg += rslt.unwrap(); // concat regions
return sequence<Tail...>::invoke(loc, std::move(reg), first);
}
static std::string pattern()
{
return concat_to_string(Head::pattern(), sequence<Tail...>::pattern());
}
};
template<typename Head>
@@ -218,19 +201,18 @@ struct sequence<Head>
{
// would be called from sequence<T ...>::invoke only.
template<typename Cont, typename Iterator>
static result<region<Cont>, std::string>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
reg += rslt.unwrap(); // concat regions
return ok(reg);
}
static std::string pattern() {return Head::pattern();}
};
template<typename ... Ts>
@@ -240,7 +222,8 @@ template<typename Head, typename ... Tail>
struct either<Head, Tail...>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
@@ -249,26 +232,18 @@ struct either<Head, Tail...>
if(rslt.is_ok()) {return rslt;}
return either<Tail...>::invoke(loc);
}
static std::string pattern()
{
return concat_to_string('(', Head::pattern(), ")|", either<Tail...>::pattern());
}
};
template<typename Head>
struct either<Head>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
return Head::invoke(loc);
}
static std::string pattern()
{
return concat_to_string('(', Head::pattern(), ')');
}
};
template<typename T, typename N>
@@ -282,7 +257,8 @@ template<typename T, std::size_t N>
struct repeat<T, exactly<N>>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region<Cont> retval(loc);
const auto first = loc.iter();
@@ -291,24 +267,21 @@ struct repeat<T, exactly<N>>
auto rslt = T::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
retval += rslt.unwrap();
}
return ok(std::move(retval));
}
static std::string pattern()
{
return concat_to_string('(', T::pattern(), "){", N, '}');
}
};
template<typename T, std::size_t N>
struct repeat<T, at_least<N>>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region<Cont> retval(loc);
@@ -318,8 +291,8 @@ struct repeat<T, at_least<N>>
auto rslt = T::invoke(loc);
if(rslt.is_err())
{
loc.iter() = first;
return err(rslt.unwrap_err());
loc.reset(first);
return none();
}
retval += rslt.unwrap();
}
@@ -333,17 +306,14 @@ struct repeat<T, at_least<N>>
retval += rslt.unwrap();
}
}
static std::string pattern()
{
return concat_to_string('(',T::pattern(), "){", N, ",}");
}
};
template<typename T>
struct repeat<T, unlimited>
{
template<typename Cont>
static result<region<Cont>, std::string> invoke(location<Cont>& loc)
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region<Cont> retval(loc);
while(true)
@@ -356,7 +326,6 @@ struct repeat<T, unlimited>
retval += rslt.unwrap();
}
}
static std::string pattern() {return concat_to_string('(', T::pattern(), ")*");}
};
} // detail

View File

@@ -1,7 +1,7 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_DATETIME
#define TOML11_DATETIME
#ifndef TOML11_DATETIME_HPP
#define TOML11_DATETIME_HPP
#include <chrono>
#include <tuple>
#include <array>
@@ -25,20 +25,22 @@ 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.");
}
if (!result) { throw std::runtime_error("localtime_r failed."); }
return dst;
}
#elif _MSC_VER
inline std::tm localtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::localtime_s(&dst, src);
if (result) { throw std::runtime_error("localtime_s failed."); }
return dst;
}
#else
// XXX: On Windows, std::localtime is thread-safe because they uses thread-local
// storage to store the instance of std::tm. On the other platforms, it may not
// be thread-safe.
inline std::tm localtime_s(const std::time_t* src)
{
const auto result = std::localtime(src);
if(!result) {throw std::runtime_error("localtime failed.");}
if (!result) { throw std::runtime_error("localtime failed."); }
return *result;
}
#endif
@@ -332,17 +334,10 @@ operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
os << 'Z';
return os;
}
if(static_cast<int>(offset.hour) * static_cast<int>(offset.minute) < 0)
{
const int min = static_cast<int>(offset.hour) * 60 + offset.minute;
if(min < 0){os << '-';} else {os << '+';}
os << std::setfill('0') << std::setw(2) << min / 60 << ':';
os << std::setfill('0') << std::setw(2) << min % 60;
return os;
}
if(offset.hour < 0){os << '-';} else {os << '+';}
os << std::setfill('0') << std::setw(2) << static_cast<int>(offset.hour) << ':';
os << std::setfill('0') << std::setw(2) << static_cast<int>(offset.minute);
int minute = static_cast<int>(offset.hour) * 60 + offset.minute;
if(minute < 0){os << '-'; minute = std::abs(minute);} else {os << '+';}
os << std::setfill('0') << std::setw(2) << minute / 60 << ':';
os << std::setfill('0') << std::setw(2) << minute % 60;
return os;
}
@@ -358,21 +353,21 @@ struct local_datetime
explicit local_datetime(const std::chrono::system_clock::time_point& tp)
{
const auto t = std::chrono::system_clock::to_time_t(tp);
std::tm time = detail::localtime_s(&t);
std::tm ltime = detail::localtime_s(&t);
this->date = local_date(time);
this->time = local_time(time);
this->date = local_date(ltime);
this->time = local_time(ltime);
// std::tm lacks subsecond information, so diff between tp and tm
// can be used to get millisecond & microsecond information.
const auto t_diff = tp -
std::chrono::system_clock::from_time_t(std::mktime(&time));
this->time.millisecond = std::chrono::duration_cast<
std::chrono::milliseconds>(t_diff).count();
this->time.microsecond = std::chrono::duration_cast<
std::chrono::microseconds>(t_diff).count();
this->time.nanosecond = std::chrono::duration_cast<
std::chrono::nanoseconds >(t_diff).count();
std::chrono::system_clock::from_time_t(std::mktime(&ltime));
this->time.millisecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
this->time.microsecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());
this->time.nanosecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::nanoseconds >(t_diff).count());
}
explicit local_datetime(const std::time_t t)

View File

@@ -1,7 +1,7 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_EXCEPTION
#define TOML11_EXCEPTION
#ifndef TOML11_EXCEPTION_HPP
#define TOML11_EXCEPTION_HPP
#include <stdexcept>
#include <string>

20
toml/from.hpp Normal file
View File

@@ -0,0 +1,20 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_FROM_HPP
#define TOML11_FROM_HPP
#include "traits.hpp"
namespace toml
{
template<typename T>
struct from;
// {
// static T from_toml(const toml::value& v)
// {
// // User-defined conversions ...
// }
// };
} // toml
#endif // TOML11_FROM_HPP

View File

@@ -1,7 +1,7 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_FROM_TOML
#define TOML11_FROM_TOML
#ifndef TOML11_FROM_TOML_HPP
#define TOML11_FROM_TOML_HPP
#include "get.hpp"
namespace toml
@@ -51,7 +51,7 @@ struct from_toml_tie_impl
template<typename ... Ts>
struct from_toml_tie_impl<0, Ts...>
{
static void invoke(std::tuple<Ts& ...> tie, const toml::value& v)
static void invoke(std::tuple<Ts& ...>, const toml::value&)
{
return;
}

View File

@@ -1,7 +1,8 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_GET
#define TOML11_GET
#ifndef TOML11_GET_HPP
#define TOML11_GET_HPP
#include "from.hpp"
#include "result.hpp"
#include "value.hpp"
#include <algorithm>
@@ -107,12 +108,24 @@ inline std::string get(value&& v)
return std::move(v.cast<value_t::String>().str);
}
// ============================================================================
// std::string_view
#if __cplusplus >= 201703L
template<typename T, typename std::enable_if<
std::is_same<T, std::string_view>::value, std::nullptr_t>::type = nullptr>
inline std::string_view get(const value& v)
{
return std::string_view(v.cast<value_t::String>().str);
}
#endif
// ============================================================================
// std::chrono::duration from toml::local_time.
template<typename T, typename std::enable_if<
detail::is_chrono_duration<T>::value, std::nullptr_t>::type = nullptr>
inline T get(value& v)
inline T get(const value& v)
{
return std::chrono::duration_cast<T>(
std::chrono::nanoseconds(v.cast<value_t::LocalTime>()));
@@ -124,7 +137,7 @@ inline T get(value& v)
template<typename T, typename std::enable_if<
std::is_same<std::chrono::system_clock::time_point, T>::value,
std::nullptr_t>::type = nullptr>
inline T get(value& v)
inline T get(const value& v)
{
switch(v.type())
{
@@ -173,6 +186,20 @@ template<typename T, typename std::enable_if<detail::conjunction<
>::value, std::nullptr_t>::type = nullptr>
T get(const toml::value& v);
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
detail::has_from_toml_method<T>, // but has from_toml(toml::value) memfn
std::is_default_constructible<T> // and default constructible
>::value, std::nullptr_t>::type = nullptr>
T get(const toml::value& v);
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>> // not a toml::value
>::value, std::nullptr_t>::type = nullptr,
std::size_t = sizeof(::toml::from<T>) // and has from<T> specialization
>
T get(const toml::value& v);
// ============================================================================
// array-like types; most likely STL container, like std::vector, etc.
@@ -249,7 +276,7 @@ namespace detail
{
template<typename T, std::size_t ...I>
T get_tuple_impl(const toml::Array& a, index_sequence<I...>)
T get_tuple_impl(const toml::array& a, index_sequence<I...>)
{
return std::make_tuple(
::toml::get<typename std::tuple_element<I, T>::type>(a.at(I))...);
@@ -297,6 +324,29 @@ T get(const toml::value& v)
return map;
}
// ============================================================================
// user-defined, but compatible types.
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
detail::has_from_toml_method<T>, // but has from_toml(toml::value) memfn
std::is_default_constructible<T> // and default constructible
>::value, std::nullptr_t>::type>
T get(const toml::value& v)
{
T ud;
ud.from_toml(v);
return ud;
}
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>> // not a toml::value
>::value, std::nullptr_t>::type, std::size_t> // and has from<T>
T get(const toml::value& v)
{
return ::toml::from<T>::from_toml(v);
}
// ============================================================================
// find and get
@@ -382,13 +432,14 @@ find(toml::value&& v, const toml::key& ky)
// ============================================================================
// get_or
// get_or(value, fallback)
template<typename T>
decltype(::toml::get<typename std::remove_cv<
typename std::remove_reference<T>::type>::type>(
std::declval<const toml::value&>()))
get_or(const toml::value& v, T&& opt)
// ----------------------------------------------------------------------------
// specialization for the exact toml types (return type becomes lvalue ref)
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T const& get_or(const toml::value& v, const T& opt)
{
try
{
@@ -397,14 +448,12 @@ get_or(const toml::value& v, T&& opt)
}
catch(...)
{
return std::forward<T>(opt);
return opt;
}
}
template<typename T>
decltype(::toml::get<typename std::remove_cv<
typename std::remove_reference<T>::type>::type>(
std::declval<toml::value&>()))
get_or(toml::value& v, T&& opt)
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T& get_or(toml::value& v, T& opt)
{
try
{
@@ -413,75 +462,279 @@ get_or(toml::value& v, T&& opt)
}
catch(...)
{
return std::forward<T>(opt);
return opt;
}
}
template<typename T>
decltype(::toml::get<typename std::remove_cv<
typename std::remove_reference<T>::type>::type>(
std::declval<toml::value&&>()))
get_or(toml::value&& v, T&& opt)
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T&& get_or(toml::value&& v, T&& opt)
{
try
{
return get<typename std::remove_cv<
typename std::remove_reference<T>::type>::type>(std::move(v));
typename std::remove_reference<T>::type>::type>(v);
}
catch(...)
{
return opt;
}
}
// ----------------------------------------------------------------------------
// specialization for std::string (return type becomes lvalue ref)
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string const& get_or(const toml::value& v, const T& opt)
{
try
{
return get<std::string>(v);
}
catch(...)
{
return opt;
}
}
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string& get_or(toml::value& v, T& opt)
{
try
{
return get<std::string>(v);
}
catch(...)
{
return opt;
}
}
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string get_or(toml::value&& v, T&& opt)
{
try
{
return get<std::string>(v);
}
catch(...)
{
return std::forward<T>(opt);
}
}
template<typename T>
auto get_or(const toml::table& tab, const toml::key& ky, T&& opt)
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
template<typename T, typename std::enable_if<
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
std::nullptr_t>::type = nullptr>
std::string get_or(const toml::value& v, T&& opt)
{
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
}
template<typename T>
auto get_or(toml::table& tab, const toml::key& ky, T&& opt)
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
{
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return ::toml::get_or(tab[ky], std::forward<T>(opt));
}
template<typename T>
auto get_or(toml::table&& tab, const toml::key& ky, T&& opt)
-> decltype(get_or(std::declval<value&&>(), std::forward<T>(opt)))
{
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
try
{
return get<std::string>(v);
}
catch(...)
{
return std::string(opt);
}
}
template<typename T>
auto get_or(const toml::value& v, const toml::key& ky, T&& opt)
-> decltype(get_or(std::declval<value const&>(), std::forward<T>(opt)))
// ----------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<std::is_same<std::string,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<detail::is_string_literal<
typename std::remove_reference<T>::type>>
>::value, std::nullptr_t>::type = nullptr>
T get_or(const toml::value& v, T&& opt)
{
if(v.type() != toml::value_t::Table){return std::forward<T>(opt);}
try
{
return get<typename std::remove_cv<
typename std::remove_reference<T>::type>::type>(v);
}
catch(...)
{
return T(std::move(opt));
}
}
// ===========================================================================
// find_or(value, key, fallback)
// ---------------------------------------------------------------------------
// exact types (return type can be a reference)
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T const& find_or(const toml::value& v, const toml::key& ky, const T& opt)
{
if(!v.is_table()) {return opt;}
const auto& tab = toml::get<toml::table>(v);
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return ::toml::get_or(tab.at(ky), std::forward<T>(opt));
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), opt);
}
template<typename T>
auto get_or(toml::value& v, const toml::key& ky, T&& opt)
-> decltype(get_or(std::declval<value&>(), std::forward<T>(opt)))
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T& find_or(toml::value& v, const toml::key& ky, T& opt)
{
if(v.type() != toml::value_t::Table){return std::forward<T>(opt);}
if(!v.is_table()) {return opt;}
auto& tab = toml::get<toml::table>(v);
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return ::toml::get_or(tab[ky], std::forward<T>(opt));
if(tab.count(ky) == 0) {return opt;}
return get_or(tab[ky], opt);
}
template<typename T>
auto get_or(toml::value&& v, const toml::key& ky, T&& opt)
-> decltype(get_or(std::declval<value&&>(), std::forward<T>(opt)))
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T&& find_or(toml::value&& v, const toml::key& ky, T&& opt)
{
if(v.type() != toml::value_t::Table){return std::forward<T>(opt);}
if(!v.is_table()) {return opt;}
auto tab = toml::get<toml::table>(std::move(v));
if(tab.count(ky) == 0) {return opt;}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// std::string (return type can be a reference)
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string const& find_or(const toml::value& v, const toml::key& ky, const T& opt)
{
if(!v.is_table()) {return opt;}
const auto& tab = toml::get<toml::table>(v);
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), opt);
}
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string& find_or(toml::value& v, const toml::key& ky, T& opt)
{
if(!v.is_table()) {return opt;}
auto& tab = toml::get<toml::table>(v);
if(tab.count(ky) == 0) {return opt;}
return get_or(tab[ky], opt);
}
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string find_or(toml::value&& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return std::forward<T>(opt);}
auto tab = toml::get<toml::table>(std::move(v));
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return ::toml::get_or(std::move(tab[ky]), std::forward<T>(opt));
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// string literal (deduced as std::string)
template<typename T, typename std::enable_if<
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
std::nullptr_t>::type = nullptr>
std::string find_or(const toml::value& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return opt;}
const auto& tab = toml::get<toml::table>(v);
if(tab.count(ky) == 0) {return std::string(opt);}
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<std::is_same<std::string,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<detail::is_string_literal<
typename std::remove_reference<T>::type>>
>::value, std::nullptr_t>::type = nullptr>
T find_or(const toml::value& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return opt;}
const auto& tab = toml::get<toml::table>(v);
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// toml::find(table)
// ---------------------------------------------------------------------------
// exact types (return type can be a reference)
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T const& find_or(const toml::table& tab, const toml::key& ky, const T& opt)
{
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), opt);
}
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T& find_or(toml::table& tab, const toml::key& ky, T& opt)
{
if(tab.count(ky) == 0) {return opt;}
return get_or(tab[ky], opt);
}
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
T&& find_or(toml::table&& tab, const toml::key& ky, T&& opt)
{
if(tab.count(ky) == 0) {return opt;}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// std::string (return type can be a reference)
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string const& find_or(const toml::table& tab, const toml::key& ky, const T& opt)
{
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), opt);
}
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string& find_or(toml::table& tab, const toml::key& ky, T& opt)
{
if(tab.count(ky) == 0) {return opt;}
return get_or(tab[ky], opt);
}
template<typename T, typename std::enable_if<
std::is_same<T, std::string>::value, std::nullptr_t>::type = nullptr>
std::string find_or(toml::table&& tab, const toml::key& ky, T&& opt)
{
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// string literal (deduced as std::string)
template<typename T, typename std::enable_if<
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
std::nullptr_t>::type = nullptr>
std::string find_or(const toml::table& tab, const toml::key& ky, T&& opt)
{
if(tab.count(ky) == 0) {return std::string(opt);}
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<std::is_same<std::string,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
detail::negation<detail::is_string_literal<
typename std::remove_reference<T>::type>>
>::value, std::nullptr_t>::type = nullptr>
T find_or(const toml::table& tab, const toml::key& ky, T&& opt)
{
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ============================================================================

20
toml/into.hpp Normal file
View File

@@ -0,0 +1,20 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_INTO_HPP
#define TOML11_INTO_HPP
#include "traits.hpp"
namespace toml
{
template<typename T>
struct into;
// {
// static toml::value into_toml(const T& user_defined_type)
// {
// // User-defined conversions ...
// }
// };
} // toml
#endif // TOML11_INTO_HPP

91
toml/literal.hpp Normal file
View File

@@ -0,0 +1,91 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_LITERAL_HPP
#define TOML11_LITERAL_HPP
#include "parser.hpp"
namespace toml
{
inline namespace literals
{
inline namespace toml_literals
{
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
{
::toml::detail::location<std::vector<char>>
loc(/* filename = */ std::string("TOML literal encoded in a C++ code"),
/* contents = */ std::vector<char>(str, str + len));
// if there are some comments or empty lines, skip them.
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
::toml::detail::maybe<::toml::detail::lex_ws>,
::toml::detail::maybe<::toml::detail::lex_comment>,
::toml::detail::lex_newline
>, ::toml::detail::at_least<1>>;
skip_line::invoke(loc);
// if there are some whitespaces before a value, skip them.
using skip_ws = ::toml::detail::repeat<
::toml::detail::lex_ws, ::toml::detail::at_least<1>>;
skip_ws::invoke(loc);
// to distinguish arrays and tables, first check it is a table or not.
//
// "[1,2,3]"_toml; // this is an array
// "[table]"_toml; // a table that has an empty table named "table" inside.
// "[[1,2,3]]"_toml; // this is an array of arrays
// "[[table]]"_toml; // this is a table that has an array of tables inside.
//
// "[[1]]"_toml; // this can be both... (currently it becomes a table)
// "1 = [{}]"_toml; // this is a table that has an array of table named 1.
// "[[1,]]"_toml; // this is an array of arrays.
// "[[1],]"_toml; // this also.
const auto the_front = loc.iter();
const bool is_table_key = ::toml::detail::lex_std_table::invoke(loc);
loc.reset(the_front);
const bool is_aots_key = ::toml::detail::lex_array_table::invoke(loc);
loc.reset(the_front);
// 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(loc))
{
return data.unwrap();
}
}
// Note that still it can be a table, because the literal might be something
// like the following.
// ```cpp
// R"( // c++11 raw string literals
// key = "value"
// int = 42
// )"_toml;
// ```
// 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(loc))
{
loc.reset(loc.begin()); // rollback to the top of the literal
// skip needless characters for error message
skip_line::invoke(loc); // skip the first several needless lines
skip_ws::invoke(loc); // skip the first several needless whitespaces
return ::toml::value(std::move(data.unwrap()),
::toml::detail::region<std::vector<char>>(std::move(loc)));
}
else // none of them.
{
throw ::toml::syntax_error(data.unwrap_err());
}
}
} // toml_literals
} // literals
} // toml
#endif//TOML11_LITERAL_HPP

View File

@@ -33,7 +33,7 @@ parse_boolean(location<Container>& loc)
{{std::addressof(reg), "invalid token"}}));
}
}
loc.iter() = first; //rollback
loc.reset(first); //rollback
return err(format_underline("[error] toml::parse_boolean: ",
{{std::addressof(loc), "the next token is not a boolean"}}));
}
@@ -62,7 +62,7 @@ parse_binary_integer(location<Container>& loc)
}
return ok(std::make_pair(retval, token.unwrap()));
}
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error] toml::parse_binary_integer:",
{{std::addressof(loc), "the next token is not an integer"}}));
}
@@ -83,7 +83,7 @@ parse_octal_integer(location<Container>& loc)
iss >> std::oct >> retval;
return ok(std::make_pair(retval, token.unwrap()));
}
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error] toml::parse_octal_integer:",
{{std::addressof(loc), "the next token is not an integer"}}));
}
@@ -104,7 +104,7 @@ parse_hexadecimal_integer(location<Container>& loc)
iss >> std::hex >> retval;
return ok(std::make_pair(retval, token.unwrap()));
}
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error] toml::parse_hexadecimal_integer",
{{std::addressof(loc), "the next token is not an integer"}}));
}
@@ -116,10 +116,28 @@ parse_integer(location<Container>& loc)
const auto first = loc.iter();
if(first != loc.end() && *first == '0')
{
if(const auto bin = parse_binary_integer (loc)) {return bin;}
if(const auto oct = parse_octal_integer (loc)) {return oct;}
if(const auto hex = parse_hexadecimal_integer(loc)) {return hex;}
// else, maybe just zero.
const auto second = std::next(first);
if(second == loc.end()) // the token is just zero.
{
return ok(std::make_pair(0, region<Container>(loc, first, second)));
}
if(*second == 'b') {return parse_binary_integer (loc);} // 0b1100
if(*second == 'o') {return parse_octal_integer (loc);} // 0o775
if(*second == 'x') {return parse_hexadecimal_integer(loc);} // 0xC0FFEE
if(std::isdigit(*second))
{
return err(format_underline("[error] toml::parse_integer: "
"leading zero in an Integer is not allowed.",
{{std::addressof(loc), "leading zero"}}));
}
else if(std::isalpha(*second))
{
return err(format_underline("[error] toml::parse_integer: "
"unknown integer prefix appeared.",
{{std::addressof(loc), "none of 0x, 0o, 0b"}}));
}
}
if(const auto token = lex_dec_int::invoke(loc))
@@ -132,7 +150,7 @@ parse_integer(location<Container>& loc)
iss >> retval;
return ok(std::make_pair(retval, token.unwrap()));
}
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error] toml::parse_integer: ",
{{std::addressof(loc), "the next token is not an integer"}}));
}
@@ -221,7 +239,7 @@ parse_floating(location<Container>& loc)
iss >> v;
return ok(std::make_pair(v, token.unwrap()));
}
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error] toml::parse_floating: ",
{{std::addressof(loc), "the next token is not a float"}}));
}
@@ -250,11 +268,11 @@ std::string read_utf8_codepoint(const region<Container>& reg,
{
if(0xD800 <= codepoint && codepoint <= 0xDFFF)
{
std::cerr << format_underline("[warning] "
throw syntax_error(format_underline("[error] "
"toml::read_utf8_codepoint: codepoints in the range "
"[0xD800, 0xDFFF] are not valid UTF-8.", {{
std::addressof(loc), "not a valid UTF-8 codepoint"
}}) << std::endl;
}}));
}
assert(codepoint < 0xD800 || 0xDFFF < codepoint);
// 1110yyyy 10yxxxxx 10xxxxxx
@@ -262,15 +280,8 @@ std::string read_utf8_codepoint(const region<Container>& reg,
character += static_cast<unsigned char>(0x80|(codepoint >> 6 & 0x3F));
character += static_cast<unsigned char>(0x80|(codepoint & 0x3F));
}
else if(codepoint < 0x200000) // U+010000 ... U+1FFFFF
else if(codepoint < 0x110000) // U+010000 ... U+10FFFF
{
if(0x10FFFF < codepoint) // out of Unicode region
{
std::cerr << format_underline("[error] "
"toml::read_utf8_codepoint: input codepoint is too large to "
"decode as a unicode character.", {{std::addressof(loc),
"should be in [0x00..0x10FFFF]"}}) << std::endl;
}
// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
character += static_cast<unsigned char>(0xF0| codepoint >> 18);
character += static_cast<unsigned char>(0x80|(codepoint >> 12 & 0x3F));
@@ -279,9 +290,9 @@ std::string read_utf8_codepoint(const region<Container>& reg,
}
else // out of UTF-8 region
{
throw std::range_error(format_underline(concat_to_string("[error] "
"input codepoint (", str, ") is too large to encode as utf-8."),
{{std::addressof(reg), "should be in [0x00..0x10FFFF]"}}));
throw syntax_error(format_underline("[error] toml::read_utf8_codepoint:"
" input codepoint is too large.",
{{std::addressof(loc), "should be in [0x00..0x10FFFF]"}}));
}
return character;
}
@@ -295,16 +306,16 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
return err(format_underline("[error]: toml::parse_escape_sequence: ", {{
std::addressof(loc), "the next token is not a backslash \"\\\""}}));
}
++loc.iter();
loc.advance();
switch(*loc.iter())
{
case '\\':{++loc.iter(); return ok(std::string("\\"));}
case '"' :{++loc.iter(); return ok(std::string("\""));}
case 'b' :{++loc.iter(); return ok(std::string("\b"));}
case 't' :{++loc.iter(); return ok(std::string("\t"));}
case 'n' :{++loc.iter(); return ok(std::string("\n"));}
case 'f' :{++loc.iter(); return ok(std::string("\f"));}
case 'r' :{++loc.iter(); return ok(std::string("\r"));}
case '\\':{loc.advance(); return ok(std::string("\\"));}
case '"' :{loc.advance(); return ok(std::string("\""));}
case 'b' :{loc.advance(); return ok(std::string("\b"));}
case 't' :{loc.advance(); return ok(std::string("\t"));}
case 'n' :{loc.advance(); return ok(std::string("\n"));}
case 'f' :{loc.advance(); return ok(std::string("\f"));}
case 'r' :{loc.advance(); return ok(std::string("\r"));}
case 'u' :
{
if(const auto token = lex_escape_unicode_short::invoke(loc))
@@ -315,7 +326,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
{
return err(format_underline("[error] parse_escape_sequence: "
"invalid token found in UTF-8 codepoint uXXXX.",
{{std::addressof(loc), token.unwrap_err()}}));
{{std::addressof(loc), "here"}}));
}
}
case 'U':
@@ -328,7 +339,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
{
return err(format_underline("[error] parse_escape_sequence: "
"invalid token found in UTF-8 codepoint Uxxxxxxxx",
{{std::addressof(loc), token.unwrap_err()}}));
{{std::addressof(loc), "here"}}));
}
}
}
@@ -338,7 +349,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
"escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}},
/* Hints = */{"if you want to write backslash as just one backslash, "
"use literal string like: regex = '<\\i\\c*\\s*>'"});
loc.iter() = first;
loc.reset(first);
return err(msg);
}
@@ -350,7 +361,7 @@ parse_ml_basic_string(location<Container>& loc)
if(const auto token = lex_ml_basic_string::invoke(loc))
{
auto inner_loc = loc;
inner_loc.iter() = first;
inner_loc.reset(first);
std::string retval;
retval.reserve(token.unwrap().size());
@@ -365,7 +376,7 @@ parse_ml_basic_string(location<Container>& loc)
// immediate newline is ignored (if exists)
/* discard return value */ lex_newline::invoke(inner_loc);
delim = err("tmp");
delim = none();
while(!delim)
{
using lex_unescaped_seq = repeat<
@@ -394,8 +405,10 @@ parse_ml_basic_string(location<Container>& loc)
}
else
{
loc.iter() = first;
return err(token.unwrap_err());
loc.reset(first);
return err(format_underline("[error] toml::parse_ml_basic_string: "
"the next token is not a multiline string",
{{std::addressof(loc), "here"}}));
}
}
@@ -407,7 +420,7 @@ parse_basic_string(location<Container>& loc)
if(const auto token = lex_basic_string::invoke(loc))
{
auto inner_loc = loc;
inner_loc.iter() = first;
inner_loc.reset(first);
auto quot = lex_quotation_mark::invoke(inner_loc);
if(!quot)
@@ -419,7 +432,7 @@ parse_basic_string(location<Container>& loc)
std::string retval;
retval.reserve(token.unwrap().size());
quot = err("tmp");
quot = none();
while(!quot)
{
using lex_unescaped_seq = repeat<lex_basic_unescaped, unlimited>;
@@ -443,8 +456,10 @@ parse_basic_string(location<Container>& loc)
}
else
{
loc.iter() = first; // rollback
return err(token.unwrap_err());
loc.reset(first); // rollback
return err(format_underline("[error] toml::parse_basic_string: "
"the next token is not a string",
{{std::addressof(loc), "here"}}));
}
}
@@ -482,8 +497,10 @@ parse_ml_literal_string(location<Container>& loc)
}
else
{
loc.iter() = first; // rollback
return err(token.unwrap_err());
loc.reset(first); // rollback
return err(format_underline("[error] toml::parse_ml_literal_string: "
"the next token is not a multiline literal string",
{{std::addressof(loc), "here"}}));
}
}
@@ -519,8 +536,10 @@ parse_literal_string(location<Container>& loc)
}
else
{
loc.iter() = first; // rollback
return err(token.unwrap_err());
loc.reset(first); // rollback
return err(format_underline("[error] toml::parse_literal_string: "
"the next token is not a literal string",
{{std::addressof(loc), "here"}}));
}
}
@@ -528,10 +547,30 @@ template<typename Container>
result<std::pair<toml::string, region<Container>>, std::string>
parse_string(location<Container>& loc)
{
if(const auto rslt = parse_ml_basic_string(loc)) {return rslt;}
if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;}
if(const auto rslt = parse_basic_string(loc)) {return rslt;}
if(const auto rslt = parse_literal_string(loc)) {return rslt;}
if(loc.iter() != loc.end() && *(loc.iter()) == '"')
{
if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '"' &&
loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '"')
{
return parse_ml_basic_string(loc);
}
else
{
return parse_basic_string(loc);
}
}
else if(loc.iter() != loc.end() && *(loc.iter()) == '\'')
{
if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '\'' &&
loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '\'')
{
return parse_ml_literal_string(loc);
}
else
{
return parse_literal_string(loc);
}
}
return err(format_underline("[error] toml::parse_string: ",
{{std::addressof(loc), "the next token is not a string"}}));
}
@@ -548,31 +587,25 @@ parse_local_date(location<Container>& loc)
const auto y = lex_date_fullyear::invoke(inner_loc);
if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
{
const std::string msg = y.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `-`");
throw internal_error(format_underline("[error]: "
"toml::parse_inner_local_date: invalid year format",
{{std::addressof(inner_loc), msg}}));
{{std::addressof(inner_loc), "should be `-`"}}));
}
++inner_loc.iter();
inner_loc.advance();
const auto m = lex_date_month::invoke(inner_loc);
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
{
const std::string msg = m.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `-`");
throw internal_error(format_underline("[error]: "
"toml::parse_local_date: invalid month format",
{{std::addressof(inner_loc), msg}}));
{{std::addressof(inner_loc), "should be `-`"}}));
}
++inner_loc.iter();
inner_loc.advance();
const auto d = lex_date_mday::invoke(inner_loc);
if(!d)
{
throw internal_error(format_underline("[error]: "
"toml::parse_local_date: invalid day format",
{{std::addressof(inner_loc), d.unwrap_err()}}));
{{std::addressof(inner_loc), "here"}}));
}
return ok(std::make_pair(local_date(
static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0)),
@@ -583,7 +616,7 @@ parse_local_date(location<Container>& loc)
}
else
{
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error]: toml::parse_local_date: ",
{{std::addressof(loc), "the next token is not a local_date"}}));
}
@@ -601,31 +634,25 @@ parse_local_time(location<Container>& loc)
const auto h = lex_time_hour::invoke(inner_loc);
if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
{
const std::string msg = h.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `:`");
throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid year format",
{{std::addressof(inner_loc), msg}}));
{{std::addressof(inner_loc), "should be `:`"}}));
}
++inner_loc.iter();
inner_loc.advance();
const auto m = lex_time_minute::invoke(inner_loc);
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
{
const std::string msg = m.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `:`");
throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid month format",
{{std::addressof(inner_loc), msg}}));
{{std::addressof(inner_loc), "should be `:`"}}));
}
++inner_loc.iter();
inner_loc.advance();
const auto s = lex_time_second::invoke(inner_loc);
if(!s)
{
throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid second format",
{{std::addressof(inner_loc), s.unwrap_err()}}));
{{std::addressof(inner_loc), "here"}}));
}
local_time time(
static_cast<std::int8_t>(from_string<int>(h.unwrap().str(), 0)),
@@ -661,14 +688,14 @@ parse_local_time(location<Container>& loc)
{
throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid subsecond format",
{{std::addressof(inner_loc), secfrac.unwrap_err()}}));
{{std::addressof(inner_loc), "here"}}));
}
}
return ok(std::make_pair(time, token.unwrap()));
}
else
{
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error]: toml::parse_local_time: ",
{{std::addressof(loc), "the next token is not a local_time"}}));
}
@@ -685,20 +712,18 @@ parse_local_datetime(location<Container>& loc)
const auto date = parse_local_date(inner_loc);
if(!date || inner_loc.iter() == inner_loc.end())
{
const std::string msg = date.map_err_or_else(
[](const std::string& msg) {return msg;}, "date, not datetime");
throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format",
{{std::addressof(inner_loc), msg}}));
{{std::addressof(inner_loc), "date, not datetime"}}));
}
const char delim = *(inner_loc.iter()++);
const char delim = *(inner_loc.iter());
if(delim != 'T' && delim != 't' && delim != ' ')
{
throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format",
{{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}));
}
inner_loc.advance();
const auto time = parse_local_time(inner_loc);
if(!time)
{
@@ -712,7 +737,7 @@ parse_local_datetime(location<Container>& loc)
}
else
{
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error]: toml::parse_local_datetime: ",
{{std::addressof(loc), "the next token is not a local_datetime"}}));
}
@@ -729,12 +754,9 @@ parse_offset_datetime(location<Container>& loc)
const auto datetime = parse_local_datetime(inner_loc);
if(!datetime || inner_loc.iter() == inner_loc.end())
{
const std::string msg = datetime.map_err_or_else(
[](const std::string& msg){return msg;}, "date, not datetime");
throw internal_error(format_underline("[error]: "
"toml::parse_offset_datetime: invalid datetime format",
{{std::addressof(inner_loc), msg}}));
{{std::addressof(inner_loc), "date, not datetime"}}));
}
time_offset offset(0, 0);
if(const auto ofs = lex_time_numoffset::invoke(inner_loc))
@@ -762,9 +784,9 @@ parse_offset_datetime(location<Container>& loc)
}
else
{
loc.iter() = first;
loc.reset(first);
return err(format_underline("[error]: toml::parse_offset_datetime: ",
{{std::addressof(loc), "the next token is not a local_datetime"}}));
{{std::addressof(loc), "the next token is not a offset_datetime"}}));
}
}
@@ -823,7 +845,7 @@ parse_key(location<Container>& loc)
}
else if(*inner_loc.iter() == '.')
{
++inner_loc.iter(); // to skip `.`
inner_loc.advance(); // to skip `.`
}
else
{
@@ -834,7 +856,7 @@ parse_key(location<Container>& loc)
}
return ok(std::make_pair(keys, reg));
}
loc.iter() = first;
loc.reset(first);
// simple key -> foo
if(const auto smpl = parse_simple_key(loc))
@@ -863,7 +885,7 @@ parse_array(location<Container>& loc)
{
return err("[error] toml::parse_array: token is not an array");
}
++loc.iter();
loc.advance();
using lex_ws_comment_newline = repeat<
either<lex_wschar, lex_newline, lex_comment>, unlimited>;
@@ -875,7 +897,7 @@ parse_array(location<Container>& loc)
if(loc.iter() != loc.end() && *loc.iter() == ']')
{
++loc.iter(); // skip ']'
loc.advance(); // skip ']'
return ok(std::make_pair(retval,
region<Container>(loc, first, loc.iter())));
}
@@ -885,7 +907,7 @@ parse_array(location<Container>& loc)
if(!retval.empty() && retval.front().type() != val.as_ok().type())
{
auto array_start_loc = loc;
array_start_loc.iter() = first;
array_start_loc.reset(first);
throw syntax_error(format_underline("[error] toml::parse_array: "
"type of elements should be the same each other.", {
@@ -905,7 +927,7 @@ parse_array(location<Container>& loc)
else
{
auto array_start_loc = loc;
array_start_loc.iter() = first;
array_start_loc.reset(first);
throw syntax_error(format_underline("[error] toml::parse_array: "
"value having invalid format appeared in an array", {
@@ -921,14 +943,14 @@ parse_array(location<Container>& loc)
lex_ws_comment_newline::invoke(loc);
if(loc.iter() != loc.end() && *loc.iter() == ']')
{
++loc.iter(); // skip ']'
loc.advance(); // skip ']'
return ok(std::make_pair(retval,
region<Container>(loc, first, loc.iter())));
}
else
{
auto array_start_loc = loc;
array_start_loc.iter() = first;
array_start_loc.reset(first);
throw syntax_error(format_underline("[error] toml::parse_array:"
" missing array separator `,` after a value", {
@@ -938,7 +960,7 @@ parse_array(location<Container>& loc)
}
}
}
loc.iter() = first;
loc.reset(first);
throw syntax_error(format_underline("[error] toml::parse_array: "
"array did not closed by `]`",
{{std::addressof(loc), "should be closed"}}));
@@ -957,7 +979,7 @@ parse_key_value_pair(location<Container>& loc)
// key. then we need to show error as "empty key is not allowed".
if(const auto keyval_sep = lex_keyval_sep::invoke(loc))
{
loc.iter() = first;
loc.reset(first);
msg = format_underline("[error] toml::parse_key_value_pair: "
"empty key is not allowed.",
{{std::addressof(loc), "key expected before '='"}});
@@ -986,7 +1008,7 @@ parse_key_value_pair(location<Container>& loc)
"missing key-value separator `=`",
{{std::addressof(loc), "should be `=`"}});
}
loc.iter() = first;
loc.reset(first);
return err(std::move(msg));
}
@@ -995,11 +1017,11 @@ parse_key_value_pair(location<Container>& loc)
if(!val)
{
std::string msg;
loc.iter() = after_kvsp;
loc.reset(after_kvsp);
// check there is something not a comment/whitespace after `=`
if(sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>::invoke(loc))
{
loc.iter() = after_kvsp;
loc.reset(after_kvsp);
msg = format_underline("[error] toml::parse_key_value_pair: "
"missing value after key-value separator '='",
{{std::addressof(loc), "expected value, but got nothing"}});
@@ -1008,7 +1030,7 @@ parse_key_value_pair(location<Container>& loc)
{
msg = std::move(val.unwrap_err());
}
loc.iter() = first;
loc.reset(first);
return err(msg);
}
return ok(std::make_pair(std::move(key_reg.unwrap()),
@@ -1035,6 +1057,7 @@ std::string format_dotted_keys(InputIterator first, const InputIterator last)
template<typename Container>
result<std::pair<std::vector<key>, region<Container>>, std::string>
parse_table_key(location<Container>& loc);
// The following toml file is allowed.
// ```toml
// [a.b.c] # here, table `a` has element `b`.
@@ -1126,7 +1149,7 @@ insert_nested_key(table& root, const toml::value& v,
{
if(tab->count(k) == 1) // there is already an array of table
{
if(tab->at(k).is(value_t::Table))
if(tab->at(k).is_table())
{
// show special err msg for conflicting table
throw syntax_error(format_underline(concat_to_string(
@@ -1139,7 +1162,7 @@ insert_nested_key(table& root, const toml::value& v,
"this conflicts with the previous table"}
}));
}
else if(!(tab->at(k).is(value_t::Array)))
else if(!(tab->at(k).is_array()))
{
throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of table (\"",
@@ -1152,8 +1175,9 @@ insert_nested_key(table& root, const toml::value& v,
"while inserting this array-of-tables"}
}));
}
array& a = tab->at(k).template cast<toml::value_t::Array>();
if(!(a.front().is(value_t::Table)))
// the above if-else-if checks tab->at(k) is an array
array& a = tab->at(k).as_array();
if(!(a.front().is_table()))
{
throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of table (\"",
@@ -1207,7 +1231,7 @@ insert_nested_key(table& root, const toml::value& v,
if(tab->count(k) == 1)
{
if(tab->at(k).is(value_t::Table) && v.is(value_t::Table))
if(tab->at(k).is_table() && v.is_table())
{
if(!is_valid_forward_table_definition(
tab->at(k), first, iter, last))
@@ -1227,18 +1251,18 @@ insert_nested_key(table& root, const toml::value& v,
// d = 42
// [a]
// e = 2.71
auto& t = tab->at(k).cast<value_t::Table>();
for(const auto& kv : v.cast<value_t::Table>())
auto& t = tab->at(k).as_table();
for(const auto& kv : v.as_table())
{
t[kv.first] = kv.second;
}
detail::change_region(tab->at(k), key_reg);
return ok(true);
}
else if(v.is(value_t::Table) &&
tab->at(k).is(value_t::Array) &&
tab->at(k).cast<value_t::Array>().size() > 0 &&
tab->at(k).cast<value_t::Array>().front().is(value_t::Table))
else if(v.is_table() &&
tab->at(k).is_array() &&
tab->at(k).as_array().size() > 0 &&
tab->at(k).as_array().front().is_table())
{
throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of tables (\"",
@@ -1278,14 +1302,14 @@ insert_nested_key(table& root, const toml::value& v,
}
// type checking...
if(tab->at(k).is(value_t::Table))
if(tab->at(k).is_table())
{
tab = std::addressof((*tab)[k].template cast<value_t::Table>());
tab = std::addressof((*tab)[k].as_table());
}
else if(tab->at(k).is(value_t::Array)) // inserting to array-of-tables?
else if(tab->at(k).is_array()) // inserting to array-of-tables?
{
array& a = (*tab)[k].template cast<value_t::Array>();
if(!a.back().is(value_t::Table))
array& a = (*tab)[k].as_array();
if(!a.back().is_table())
{
throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: target (",
@@ -1296,7 +1320,7 @@ insert_nested_key(table& root, const toml::value& v,
{std::addressof(get_region(v)), "inserting this"}
}));
}
tab = std::addressof(a.back().template cast<value_t::Table>());
tab = std::addressof(a.back().as_table());
}
else
{
@@ -1322,17 +1346,17 @@ parse_inline_table(location<Container>& loc)
table retval;
if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
{
return err(format_underline("[error] toml::parse_inline_table: ",
return err(format_underline("[error] toml::parse_inline_table: ",
{{std::addressof(loc), "the next token is not an inline table"}}));
}
++loc.iter();
loc.advance();
// it starts from "{". it should be formatted as inline-table
while(loc.iter() != loc.end())
{
maybe<lex_ws>::invoke(loc);
if(loc.iter() != loc.end() && *loc.iter() == '}')
{
++loc.iter(); // skip `}`
loc.advance(); // skip `}`
return ok(std::make_pair(
retval, region<Container>(loc, first, loc.iter())));
}
@@ -1361,24 +1385,185 @@ parse_inline_table(location<Container>& loc)
maybe<lex_ws>::invoke(loc);
if(loc.iter() != loc.end() && *loc.iter() == '}')
{
++loc.iter(); // skip `}`
loc.advance(); // skip `}`
return ok(std::make_pair(
retval, region<Container>(loc, first, loc.iter())));
}
else if(*loc.iter() == '#' || *loc.iter() == '\r' || *loc.iter() == '\n')
{
throw syntax_error(format_underline("[error] "
"toml::parse_inline_table: missing curly brace `}`",
{{std::addressof(loc), "should be `}`"}}));
}
else
{
throw syntax_error(format_underline("[error] "
"toml:::parse_inline_table: missing table separator `,` ",
"toml::parse_inline_table: missing table separator `,` ",
{{std::addressof(loc), "should be `,`"}}));
}
}
}
loc.iter() = first;
loc.reset(first);
throw syntax_error(format_underline("[error] toml::parse_inline_table: "
"inline table did not closed by `}`",
{{std::addressof(loc), "should be closed"}}));
}
template<typename Container>
result<value_t, std::string> guess_number_type(const location<Container>& l)
{
// This function tries to find some (common) mistakes by checking characters
// that follows the last character of a value. But it is often difficult
// because some non-newline characters can appear after a value. E.g.
// spaces, tabs, commas (in an array or inline table), closing brackets
// (of an array or inline table), comment-sign (#). Since this function
// does not parse further, those characters are always allowed to be there.
location<Container> loc = l;
if(lex_offset_date_time::invoke(loc)) {return ok(value_t::OffsetDatetime);}
loc.reset(l.iter());
if(lex_local_date_time::invoke(loc))
{
// bad offset may appear after this.
if(loc.iter() != loc.end() && (*loc.iter() == '+' || *loc.iter() == '-'
|| *loc.iter() == 'Z' || *loc.iter() == 'z'))
{
return err(format_underline("[error] bad offset: should be [+-]HH:MM or Z",
{{std::addressof(loc), "[+-]HH:MM or Z"}},
{"pass: +09:00, -05:30", "fail: +9:00, -5:30"}));
}
return ok(value_t::LocalDatetime);
}
loc.reset(l.iter());
if(lex_local_date::invoke(loc))
{
// bad time may appear after this.
// A space is allowed as a delimiter between local time. But there are
// both cases in which a space becomes valid or invalid.
// - invalid: 2019-06-16 7:00:00
// - valid : 2019-06-16 07:00:00
if(loc.iter() != loc.end())
{
const auto c = *loc.iter();
if(c == 'T' || c == 't')
{
return err(format_underline("[error] bad time: should be HH:MM:SS.subsec",
{{std::addressof(loc), "HH:MM:SS.subsec"}},
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
"fail: 1979-05-27T7:32:00, 1979-05-27 17:32"}));
}
if('0' <= c && c <= '9')
{
return err(format_underline("[error] bad time: missing T",
{{std::addressof(loc), "T or space required here"}},
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
"fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
}
if(c == ' ' && std::next(loc.iter()) != loc.end() &&
('0' <= *std::next(loc.iter()) && *std::next(loc.iter())<= '9'))
{
loc.advance();
return err(format_underline("[error] bad time: should be HH:MM:SS.subsec",
{{std::addressof(loc), "HH:MM:SS.subsec"}},
{"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
"fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
}
}
return ok(value_t::LocalDate);
}
loc.reset(l.iter());
if(lex_local_time::invoke(loc)) {return ok(value_t::LocalTime);}
loc.reset(l.iter());
if(lex_float::invoke(loc))
{
if(loc.iter() != loc.end() && *loc.iter() == '_')
{
return err(format_underline("[error] bad float: `_` should be surrounded by digits",
{{std::addressof(loc), "here"}},
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
}
return ok(value_t::Float);
}
loc.reset(l.iter());
if(lex_integer::invoke(loc))
{
if(loc.iter() != loc.end())
{
const auto c = *loc.iter();
if(c == '_')
{
return err(format_underline("[error] bad integer: `_` should be surrounded by digits",
{{std::addressof(loc), "here"}},
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
"fail: 1__000, 0123"}));
}
if('0' <= c && c <= '9')
{
// leading zero. point '0'
loc.retrace();
return err(format_underline("[error] bad integer: leading zero",
{{std::addressof(loc), "here"}},
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
"fail: 1__000, 0123"}));
}
if(c == ':' || c == '-')
{
return err(format_underline("[error] bad datetime: invalid format",
{{std::addressof(loc), "here"}},
{"pass: 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z",
"fail: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30"}));
}
if(c == '.' || c == 'e' || c == 'E')
{
return err(format_underline("[error] bad float: invalid format",
{{std::addressof(loc), "here"}},
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
}
}
return ok(value_t::Integer);
}
if(loc.iter() != loc.end() && *loc.iter() == '.')
{
return err(format_underline("[error] bad float: invalid format",
{{std::addressof(loc), "integer part required before this"}},
{"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
"fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
}
if(loc.iter() != loc.end() && *loc.iter() == '_')
{
return err(format_underline("[error] bad number: `_` should be surrounded by digits",
{{std::addressof(loc), "`_` is not surrounded by digits"}},
{"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
"fail: 1__000, 0123"}));
}
return err(format_underline("[error] bad format: unknown value appeared",
{{std::addressof(loc), "here"}}));
}
template<typename Container>
result<value_t, std::string> guess_value_type(const location<Container>& loc)
{
switch(*loc.iter())
{
case '"' : {return ok(value_t::String); }
case '\'': {return ok(value_t::String); }
case 't' : {return ok(value_t::Boolean);}
case 'f' : {return ok(value_t::Boolean);}
case '[' : {return ok(value_t::Array); }
case '{' : {return ok(value_t::Table); }
case 'i' : {return ok(value_t::Float); } // inf.
case 'n' : {return ok(value_t::Float); } // nan.
default : {return guess_number_type(loc);}
}
}
template<typename Container>
result<value, std::string> parse_value(location<Container>& loc)
{
@@ -1388,31 +1573,32 @@ result<value, std::string> parse_value(location<Container>& loc)
return err(format_underline("[error] toml::parse_value: input is empty",
{{std::addressof(loc), ""}}));
}
if(auto r = parse_string (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_array (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_inline_table (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_boolean (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_offset_datetime(loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_local_datetime (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_local_date (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_local_time (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_floating (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
if(auto r = parse_integer (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
const auto msg = format_underline("[error] toml::parse_value: "
"unknown token appeared", {{std::addressof(loc), "unknown"}});
loc.iter() = first;
return err(msg);
const auto type = guess_value_type(loc);
if(!type)
{
return err(type.unwrap_err());
}
switch(type.unwrap())
{
case value_t::Boolean : {return parse_boolean(loc); }
case value_t::Integer : {return parse_integer(loc); }
case value_t::Float : {return parse_floating(loc); }
case value_t::String : {return parse_string(loc); }
case value_t::OffsetDatetime : {return parse_offset_datetime(loc);}
case value_t::LocalDatetime : {return parse_local_datetime(loc); }
case value_t::LocalDate : {return parse_local_date(loc); }
case value_t::LocalTime : {return parse_local_time(loc); }
case value_t::Array : {return parse_array(loc); }
case value_t::Table : {return parse_inline_table(loc); }
default:
{
const auto msg = format_underline("[error] toml::parse_value: "
"unknown token appeared", {{std::addressof(loc), "unknown"}});
loc.reset(first);
return err(msg);
}
}
}
template<typename Container>
@@ -1468,7 +1654,8 @@ parse_table_key(location<Container>& loc)
}
else
{
return err(token.unwrap_err());
return err(format_underline("[error] toml::parse_table_key: "
"not a valid table key", {{std::addressof(loc), "here"}}));
}
}
@@ -1521,7 +1708,8 @@ parse_array_table_key(location<Container>& loc)
}
else
{
return err(token.unwrap_err());
return err(format_underline("[error] toml::parse_array_table_key: "
"not a valid table key", {{std::addressof(loc), "here"}}));
}
}
@@ -1547,12 +1735,12 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
const auto before = loc.iter();
if(const auto tmp = parse_array_table_key(loc)) // next table found
{
loc.iter() = before;
loc.reset(before);
return ok(tab);
}
if(const auto tmp = parse_table_key(loc)) // next table found
{
loc.iter() = before;
loc.reset(before);
return ok(tab);
}
@@ -1587,12 +1775,12 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
const auto newline = skip_line::invoke(loc);
if(!newline && loc.iter() != loc.end())
{
const auto before = loc.iter();
const auto before2 = loc.iter();
lex_ws::invoke(loc); // skip whitespace
const auto msg = format_underline("[error] toml::parse_table: "
"invalid line format", {{std::addressof(loc), concat_to_string(
"expected newline, but got '", show_char(*loc.iter()), "'.")}});
loc.iter() = before;
loc.reset(before2);
return err(msg);
}
@@ -1695,7 +1883,7 @@ inline table parse(std::istream& is, std::string fname = "unknown file")
std::memcpy(BOM.data(), loc.source()->data(), 3);
if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
{
loc.iter() += 3; // BOM found. skip.
loc.advance(3); // BOM found. skip.
}
}

View File

@@ -1,7 +1,7 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_REGION_H
#define TOML11_REGION_H
#ifndef TOML11_REGION_HPP
#define TOML11_REGION_HPP
#include "exception.hpp"
#include <memory>
#include <vector>
@@ -15,7 +15,7 @@ namespace toml
namespace detail
{
// helper function to avoid std::string(0, 'c')
// helper function to avoid std::string(0, 'c') or std::string(iter, iter)
template<typename Iterator>
std::string make_string(Iterator first, Iterator last)
{
@@ -28,9 +28,7 @@ inline std::string make_string(std::size_t len, char c)
return std::string(len, c);
}
// region in a container, normally in a file content.
// shared_ptr points the resource that the iter points.
// combinators returns this.
// region_base is a base class of location and region that are defined below.
// it will be used to generate better error messages.
struct region_base
{
@@ -48,25 +46,40 @@ struct region_base
virtual std::string line() const {return std::string("unknown line");}
virtual std::string line_num() const {return std::string("?");}
virtual std::size_t before() const noexcept {return 0;}
// length of the region
virtual std::size_t size() const noexcept {return 0;}
// number of characters in the line before the region
virtual std::size_t before() const noexcept {return 0;}
// number of characters in the line after the region
virtual std::size_t after() const noexcept {return 0;}
virtual std::string comment_before() const {return "";} // just before
virtual std::string comment_inline() const {return "";} // in the same line
virtual std::string comment() const {return "";} // concatenate
// ```toml
// # comment_before
// key = "value" # comment_inline
// ```
};
// location in a container, normally in a file content.
// shared_ptr points the resource that the iter points.
// it can be used not only for resource handling, but also error message.
//
// location represents a position in a container, which contains a file content.
// it can be considered as a region that contains only one character.
//
// it contains pointer to the file content and iterator that points the current
// location.
template<typename Container>
struct location final : public region_base
{
static_assert(std::is_same<char, typename Container::value_type>::value,"");
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");
location(std::string name, Container cont)
: source_(std::make_shared<Container>(std::move(cont))),
: source_(std::make_shared<Container>(std::move(cont))), line_number_(1),
source_name_(std::move(name)), iter_(source_->cbegin())
{}
location(const location&) = default;
@@ -77,18 +90,54 @@ struct location final : public region_base
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
const_iterator& iter() noexcept {return iter_;}
const_iterator iter() const noexcept {return iter_;}
// this const prohibits codes like `++(loc.iter())`.
const const_iterator iter() const noexcept {return iter_;}
const_iterator begin() const noexcept {return source_->cbegin();}
const_iterator end() const noexcept {return source_->cend();}
const_iterator begin() const noexcept {return source_->cbegin();}
const_iterator end() const noexcept {return source_->cend();}
// XXX `location::line_num()` used to be implemented using `std::count` to
// count a number of '\n'. But with a long toml file (typically, 10k lines),
// it becomes intolerably slow because each time it generates error messages,
// it counts '\n' from thousands of characters. To workaround it, I decided
// to introduce `location::line_number_` member variable and synchronize it
// to the location changes the point to look. So an overload of `iter()`
// which returns mutable reference is removed and `advance()`, `retrace()`
// and `reset()` is added.
void advance(std::size_t n = 1) noexcept
{
this->line_number_ += std::count(this->iter_, this->iter_ + n, '\n');
this->iter_ += n;
return;
}
void retrace(std::size_t n = 1) noexcept
{
this->line_number_ -= std::count(this->iter_ - n, this->iter_, '\n');
this->iter_ -= n;
return;
}
void reset(const_iterator rollback) noexcept
{
// since c++11, std::distance works in both ways for random-access
// iterators and returns a negative value if `first > last`.
if(0 <= std::distance(rollback, this->iter_)) // rollback < iter
{
this->line_number_ -= std::count(rollback, this->iter_, '\n');
}
else // iter < rollback [[unlikely]]
{
this->line_number_ += std::count(this->iter_, rollback, '\n');
}
this->iter_ = rollback;
return;
}
std::string str() const override {return make_string(1, *this->iter());}
std::string name() const override {return source_name_;}
std::string line_num() const override
{
return std::to_string(1+std::count(this->begin(), this->iter(), '\n'));
return std::to_string(this->line_number_);
}
std::string line() const override
@@ -127,17 +176,26 @@ struct location final : public region_base
private:
source_ptr source_;
std::size_t line_number_;
std::string source_name_;
const_iterator iter_;
};
// region represents a range in a container, which contains a file content.
//
// 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
{
static_assert(std::is_same<char, typename Container::value_type>::value,"");
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");
// delete default constructor. source_ never be null.
region() = delete;
@@ -230,6 +288,92 @@ struct region final : public region_base
std::string name() const override {return source_name_;}
std::string comment_before() const override
{
auto iter = this->line_begin(); // points the first element
std::vector<std::pair<decltype(iter), decltype(iter)>> comments;
while(iter != this->begin())
{
iter = std::prev(iter);
using rev_iter = std::reverse_iterator<decltype(iter)>;
auto line_before = std::find(rev_iter(iter), rev_iter(this->begin()),
'\n').base();
// range [line_before, iter) represents the previous line
auto comment_found = std::find(line_before, iter, '#');
if(iter != comment_found && std::all_of(line_before, comment_found,
[](const char c) noexcept -> bool {
return c == ' ' || c == '\t';
}))
{
// the line before this range contains only a comment.
comments.push_back(std::make_pair(comment_found, iter));
}
else
{
break;
}
iter = line_before;
}
std::string com;
for(auto i = comments.crbegin(), e = comments.crend(); i!=e; ++i)
{
if(i != comments.crbegin()) {com += '\n';}
com += std::string(i->first, i->second);
}
return com;
}
std::string comment_inline() const override
{
if(this->contain_newline())
{
std::string com;
// check both the first and the last line.
const auto first_line_end =
std::find(this->line_begin(), this->last(), '\n');
const auto first_comment_found =
std::find(this->line_begin(), first_line_end, '#');
if(first_comment_found != first_line_end)
{
com += std::string(first_comment_found, first_line_end);
}
const auto last_comment_found =
std::find(this->last(), this->line_end(), '#');
if(last_comment_found != this->line_end())
{
if(!com.empty()){com += '\n';}
com += std::string(last_comment_found, this->line_end());
}
return com;
}
const auto comment_found =
std::find(this->line_begin(), this->line_end(), '#');
return std::string(comment_found, this->line_end());
}
std::string comment() const override
{
std::string com_bef = this->comment_before();
std::string com_inl = this->comment_inline();
if(!com_bef.empty() && !com_inl.empty())
{
com_bef += '\n';
return com_bef + com_inl;
}
else if(com_bef.empty())
{
return com_inl;
}
else
{
return com_bef;
}
}
private:
source_ptr source_;
@@ -293,7 +437,8 @@ inline std::string format_underline(const std::string& message,
{
// invalid
// ~~~~~~~
retval << make_string(reg->size(), '~');
const auto underline_len = std::min(reg->size(), reg->line().size());
retval << make_string(underline_len, '~');
}
retval << ' ';

View File

@@ -1,7 +1,7 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_RESULT_H
#define TOML11_RESULT_H
#ifndef TOML11_RESULT_HPP
#define TOML11_RESULT_HPP
#include "traits.hpp"
#include <type_traits>
#include <stdexcept>
@@ -113,21 +113,25 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(s);
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
result(const failure_type& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
result(success_type&& s): is_ok_(true)
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
result(failure_type&& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
template<typename U>
@@ -135,24 +139,28 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
template<typename U>
result(const failure<U>& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
template<typename U>
result(success<U>&& s): is_ok_(true)
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
template<typename U>
result(failure<U>&& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
result& operator=(const success_type& s)
@@ -161,6 +169,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(s);
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
result& operator=(const failure_type& f)
@@ -169,6 +178,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
result& operator=(success_type&& s)
@@ -177,6 +187,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
result& operator=(failure_type&& f)
@@ -185,6 +196,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
@@ -195,6 +207,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
template<typename U>
@@ -204,6 +217,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
template<typename U>
@@ -213,6 +227,7 @@ struct result
this->is_ok_ = true;
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
assert(tmp == std::addressof(this->succ));
(void)tmp;
return *this;
}
template<typename U>
@@ -222,6 +237,7 @@ struct result
this->is_ok_ = false;
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
assert(tmp == std::addressof(this->fail));
(void)tmp;
return *this;
}
@@ -233,11 +249,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
result(result&& other): is_ok_(other.is_ok())
@@ -246,11 +264,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
@@ -261,11 +281,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
template<typename U, typename F>
@@ -275,11 +297,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
}
@@ -290,11 +314,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -306,11 +332,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -324,11 +352,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -341,11 +371,13 @@ struct result
{
auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
is_ok_ = other.is_ok();
return *this;
@@ -660,5 +692,26 @@ void swap(result<T, E>& lhs, result<T, E>& rhs)
// return lhs.is_ok() ? lhs : rhs;
// }
// ----------------------------------------------------------------------------
// re-use result<T, E> as a optional<T> with none_t
namespace detail
{
struct none_t {};
inline bool operator==(const none_t&, const none_t&) noexcept {return true;}
inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}
inline bool operator< (const none_t&, const none_t&) noexcept {return false;}
inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}
inline bool operator> (const none_t&, const none_t&) noexcept {return false;}
inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}
template<typename charT, typename traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
{
os << "none";
return os;
}
inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
} // detail
} // toml11
#endif// TOML11_RESULT_H

View File

@@ -157,7 +157,7 @@ struct serializer
std::string operator()(const array& v) const
{
if(!v.empty() && v.front().is(value_t::Table))// v is an array of tables
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, we need `table.key = [...]`.
@@ -411,7 +411,7 @@ struct serializer
// remaining non-table values will be assigned into [foo.bar], not [foo]
for(const auto kv : v)
{
if(kv.second.is(value_t::Table) || is_array_of_tables(kv.second))
if(kv.second.is_table() || is_array_of_tables(kv.second))
{
continue;
}
@@ -438,7 +438,7 @@ struct serializer
bool multiline_table_printed = false;
for(const auto& kv : v)
{
if(!kv.second.is(value_t::Table) && !is_array_of_tables(kv.second))
if(!kv.second.is_table() && !is_array_of_tables(kv.second))
{
continue; // other stuff are already serialized. skip them.
}
@@ -467,10 +467,9 @@ struct serializer
bool is_array_of_tables(const value& v) const
{
if(!v.is(value_t::Array)) {return false;}
const auto& a = v.cast<value_t::Array>();
return !a.empty() && a.front().is(value_t::Table);
if(!v.is_array()) {return false;}
const auto& a = v.as_array();
return !a.empty() && a.front().is_table();
}
private:
@@ -483,15 +482,19 @@ struct serializer
inline std::string
format(const value& v, std::size_t w = 80,
int fprec = std::numeric_limits<toml::floating>::max_digits10)
int fprec = std::numeric_limits<toml::floating>::max_digits10,
bool force_inline = false)
{
return visit(serializer(w, fprec, true), v);
// if value is a table, it is considered to be a root object.
// the root object can't be an inline table. so pass false. otherwise, true.
return visit(serializer(w, fprec, (!v.is_table()) || force_inline), v);
}
inline std::string
format(const table& t, std::size_t w = 80,
int fprec = std::numeric_limits<toml::floating>::max_digits10)
int fprec = std::numeric_limits<toml::floating>::max_digits10,
bool force_inline = false)
{
return serializer(w, fprec, true)(t);
return serializer(w, fprec, force_inline)(t);
}
template<typename charT, typename traits>
@@ -506,6 +509,18 @@ operator<<(std::basic_ostream<charT, traits>& os, const value& v)
os << visit(serializer(w, fprec, false), v);
return os;
}
template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const table& v)
{
// get status of std::setw().
const std::size_t w = os.width();
const int fprec = os.precision();
os.width(0);
// the root object can't be an inline table. so pass `false`.
os << serializer(w, fprec, false)(v);
return os;
}
} // toml
#endif// TOML11_SERIALIZER_HPP

View File

@@ -1,9 +1,14 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_STRING_H
#define TOML11_STRING_H
#ifndef TOML11_STRING_HPP
#define TOML11_STRING_HPP
#include <string>
#include <cstdint>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif
#endif
namespace toml
{
@@ -40,6 +45,17 @@ struct string
operator std::string const& () const& noexcept {return str;}
operator std::string&& () && noexcept {return std::move(str);}
#if __cplusplus >= 201703L
explicit string(std::string_view s): kind(string_t::basic), str(s){}
string(std::string_view s, string_t k): kind(k), str(s){}
string& operator=(std::string_view s)
{kind = string_t::basic; str = s; return *this;}
explicit operator std::string_view() const noexcept
{return std::string_view(str);}
#endif
string_t kind;
std::string str;
};

View File

@@ -1,49 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TO_TOML
#define TOML11_TO_TOML
#include "value.hpp"
namespace toml
{
template<typename T>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(T&& x)
{
return value(std::forward<T>(x));
}
template<typename T>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(T&& x, string_t kind)
{
return value(std::forward<T>(x), kind);
}
TOML11_MARK_AS_DEPRECATED
inline value to_toml(local_date d, local_time t)
{
return value(local_datetime(d, t));
}
TOML11_MARK_AS_DEPRECATED
inline value to_toml(local_date d, local_time t, time_offset ofs)
{
return value(offset_datetime(d, t, ofs));
}
template<typename ... Ts>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(Ts&& ... xs)
{
return value(toml::array{toml::value(std::forward<Ts>(xs)) ... });
}
TOML11_MARK_AS_DEPRECATED
inline value to_toml(std::initializer_list<std::pair<std::string, toml::value>> xs)
{
return value(toml::table(xs.begin(), xs.end()));
}
} // toml
#endif // TOML11_TO_TOML

View File

@@ -1,14 +1,23 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TRAITS
#define TOML11_TRAITS
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include <type_traits>
#include <utility>
#include <chrono>
#include <tuple>
#include <string>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus >= C++17
namespace toml
{
class value; // forward decl
namespace detail
{
@@ -45,6 +54,22 @@ struct has_resize_method_impl
template<typename T> static std::false_type check(...);
};
struct has_from_toml_method_impl
{
template<typename T>
static std::true_type check(
decltype(std::declval<T>().from_toml(std::declval<::toml::value>()))*);
template<typename T>
static std::false_type check(...);
};
struct has_into_toml_method_impl
{
template<typename T>
static std::true_type check(decltype(std::declval<T>().into_toml())*);
template<typename T>
static std::false_type check(...);
};
/// 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
@@ -62,6 +87,13 @@ 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)){};
template<typename T>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
#ifdef __INTEL_COMPILER
#undef decltype(...)
#endif
@@ -87,7 +119,7 @@ template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
// ---------------------------------------------------------------------------
// normal type checker
// type checkers
template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
@@ -101,6 +133,33 @@ 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{};
template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
has_iterator<T>, // has T::iterator
has_value_type<T>, // has T::value_type
has_key_type<T>, // has T::key_type
has_mapped_type<T> // has T::mapped_type
>{};
template<typename T> struct is_map<T&> : is_map<T>{};
template<typename T> struct is_map<T const&> : is_map<T>{};
template<typename T> struct is_map<T volatile&> : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
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
negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
has_iterator<T>, // has T::iterator
has_value_type<T> // has T::value_type
>{};
template<typename T> struct is_container<T&> : is_container<T>{};
template<typename T> struct is_container<T const&> : is_container<T>{};
template<typename T> struct is_container<T volatile&> : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
// ---------------------------------------------------------------------------
// C++14 index_sequence
@@ -142,6 +201,21 @@ using return_type_of_t = typename std::result_of<F(Args...)>::type;
#endif
// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.
template<typename T>
struct is_string_literal:
disjunction<
std::is_same<const char*, T>,
conjunction<
std::is_array<T>,
std::is_same<const char, typename std::remove_extent<T>::type>
>
>{};
}// detail
}//toml
#endif // TOML_TRAITS

View File

@@ -1,7 +1,7 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TYPES_H
#define TOML11_TYPES_H
#ifndef TOML11_TYPES_HPP
#define TOML11_TYPES_HPP
#include "datetime.hpp"
#include "string.hpp"
#include "traits.hpp"
@@ -126,61 +126,36 @@ template<> struct toml_default_type<value_t::Table > {typedef table
template<> struct toml_default_type<value_t::Empty > {typedef void type;};
template<> struct toml_default_type<value_t::Unknown > {typedef void type;};
template<typename T> struct toml_value_t {static constexpr value_t value = value_t::Unknown ;};
template<> struct toml_value_t<Boolean >{static constexpr value_t value = value_t::Boolean ;};
template<> struct toml_value_t<Integer >{static constexpr value_t value = value_t::Integer ;};
template<> struct toml_value_t<Float >{static constexpr value_t value = value_t::Float ;};
template<> struct toml_value_t<String >{static constexpr value_t value = value_t::String ;};
template<> struct toml_value_t<OffsetDatetime>{static constexpr value_t value = value_t::OffsetDatetime;};
template<> struct toml_value_t<LocalDatetime >{static constexpr value_t value = value_t::LocalDatetime ;};
template<> struct toml_value_t<LocalDate >{static constexpr value_t value = value_t::LocalDate ;};
template<> struct toml_value_t<LocalTime >{static constexpr value_t value = value_t::LocalTime ;};
template<> struct toml_value_t<Array >{static constexpr value_t value = value_t::Array ;};
template<> struct toml_value_t<Table >{static constexpr value_t value = value_t::Table ;};
template<typename T> struct toml_value_t {static constexpr value_t value = value_t::Unknown ;};
template<> struct toml_value_t<boolean >{static constexpr value_t value = value_t::Boolean ;};
template<> struct toml_value_t<integer >{static constexpr value_t value = value_t::Integer ;};
template<> struct toml_value_t<floating >{static constexpr value_t value = value_t::Float ;};
template<> struct toml_value_t<string >{static constexpr value_t value = value_t::String ;};
template<> struct toml_value_t<offset_datetime>{static constexpr value_t value = value_t::OffsetDatetime;};
template<> struct toml_value_t<local_datetime >{static constexpr value_t value = value_t::LocalDatetime ;};
template<> struct toml_value_t<local_date >{static constexpr value_t value = value_t::LocalDate ;};
template<> struct toml_value_t<local_time >{static constexpr value_t value = value_t::LocalTime ;};
template<> struct toml_value_t<array >{static constexpr value_t value = value_t::Array ;};
template<> struct toml_value_t<table >{static constexpr value_t value = value_t::Table ;};
template<typename T>
struct is_exact_toml_type : disjunction<
std::is_same<T, Boolean >,
std::is_same<T, Integer >,
std::is_same<T, Float >,
std::is_same<T, String >,
std::is_same<T, boolean >,
std::is_same<T, integer >,
std::is_same<T, floating >,
std::is_same<T, string >,
std::is_same<T, offset_datetime>,
std::is_same<T, local_datetime>,
std::is_same<T, local_date>,
std::is_same<T, local_time>,
std::is_same<T, Array >,
std::is_same<T, Table >
std::is_same<T, local_datetime >,
std::is_same<T, local_date >,
std::is_same<T, local_time >,
std::is_same<T, array >,
std::is_same<T, table >
>{};
template<typename T> struct is_exact_toml_type<T&> : is_exact_toml_type<T>{};
template<typename T> struct is_exact_toml_type<T const&> : is_exact_toml_type<T>{};
template<typename T> struct is_exact_toml_type<T volatile&> : is_exact_toml_type<T>{};
template<typename T> struct is_exact_toml_type<T const volatile&>: is_exact_toml_type<T>{};
template<typename T>
struct is_map : conjunction<
has_iterator<T>,
has_value_type<T>,
has_key_type<T>,
has_mapped_type<T>
>{};
template<typename T> struct is_map<T&> : is_map<T>{};
template<typename T> struct is_map<T const&> : is_map<T>{};
template<typename T> struct is_map<T volatile&> : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
template<typename T>
struct is_container : conjunction<
negation<is_map<T>>,
negation<std::is_same<T, std::string>>,
has_iterator<T>,
has_value_type<T>
>{};
template<typename T> struct is_container<T&> : is_container<T>{};
template<typename T> struct is_container<T const&> : is_container<T>{};
template<typename T> struct is_container<T volatile&> : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
} // detail
} // toml
#endif// TOML11_TYPES_H

View File

@@ -1,18 +1,18 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_UTILITY
#define TOML11_UTILITY
#ifndef TOML11_UTILITY_HPP
#define TOML11_UTILITY_HPP
#include "traits.hpp"
#include <utility>
#include <memory>
#include <sstream>
#if __cplusplus >= 201402L
# define TOML11_MARK_AS_DEPRECATED [[deprecated]]
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
#elif defined(__GNUC__)
# define TOML11_MARK_AS_DEPRECATED __attribute__((deprecated))
# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
# define TOML11_MARK_AS_DEPRECATED __declspec(deprecated)
# define TOML11_MARK_AS_DEPRECATED(msg) __declspec(deprecated(msg))
#else
# define TOML11_MARK_AS_DEPRECATED
#endif
@@ -79,7 +79,7 @@ std::string concat_to_string(Ts&& ... args)
template<typename T, typename U>
T from_string(const std::string& str, U&& opt)
{
T v(std::forward<U>(opt));
T v(static_cast<T>(std::forward<U>(opt)));
std::istringstream iss(str);
iss >> v;
return v;

File diff suppressed because it is too large Load Diff