Compare commits

...

76 Commits

Author SHA1 Message Date
ToruNiina
da98b6558d fix: ctor of time and null 2024-07-27 18:27:16 +09:00
ToruNiina
c433577120 feat: add key_format_info to basic_value ctor 2024-07-27 18:26:52 +09:00
ToruNiina
a39300f9d9 feat: add detail::change_region_of_key 2024-07-27 16:39:46 +09:00
ToruNiina
2193c5c201 feat(WIP): use default arg instead of overloads 2024-07-26 02:49:11 +09:00
ToruNiina
e2bbf550a0 feat(WIP): init key_region and key_fmt 2024-07-26 00:54:31 +09:00
ToruNiina
1809484542 feat: add key_fmt/region to value 2024-07-26 00:13:23 +09:00
ToruNiina
0571dd74ca feat: add key format to fwd 2024-07-26 00:11:53 +09:00
ToruNiina
19199ac82c feat: add key_format 2024-07-25 01:24:55 +09:00
ToruNiina
572781971f doc: add doc about CPM 2024-07-23 01:29:13 +09:00
ToruNiina
0072e740d5 feat [skip ci]: update single_include 2024-07-21 15:53:41 +00:00
Toru Niina
4dd83fe778 Merge pull request #258 from pinotree/read-streamsize
fix: manually cast file size to std::streamsize
2024-07-22 00:41:56 +09:00
Pino Toscano
fe19e7ee0a fix: manually cast file size to std::streamsize
When reading a file to vector, manually cast the file size (represented
as std::streamoff hidden as auto) to std::streamsize, which is the type
for std::istream::read(); this avoids the warning/error

  error: conversion from ‘long long int’ to ‘std::streamsize’ {aka ‘int’} may change value [-Werror=conversion]

This means a truncation happens on 32bit architectures, however that
seems a limitation of the standard library.
2024-07-21 10:36:40 +02:00
ToruNiina
f33ca743fb chore: bump version 4.1.0 2024-07-21 14:48:47 +09:00
ToruNiina
754c1ef879 doc: update changelogs 2024-07-21 14:48:19 +09:00
ToruNiina
911abe939e doc: update acknowledgment in README 2024-07-21 14:34:20 +09:00
ToruNiina
100d05822a feat [skip ci]: update single_include 2024-07-20 16:01:53 +00:00
ToruNiina
feda8356a3 Merge branch 'example-u8string' 2024-07-21 01:01:24 +09:00
ToruNiina
88aaefd747 Revert "ci: build examples in each cases"
This reverts commit 4d0ad7335b.
2024-07-20 22:43:00 +09:00
ToruNiina
4d0ad7335b ci: build examples in each cases 2024-07-20 21:12:09 +09:00
ToruNiina
96460a15d4 feat: support key string conversion in get<map> 2024-07-20 20:57:42 +09:00
ToruNiina
a50895cdff doc: add u8string example 2024-07-20 20:57:18 +09:00
ToruNiina
886801d00a feat [skip ci]: update single_include 2024-07-20 10:07:38 +00:00
ToruNiina
f3a1586a44 Merge branch 'u8string' into v4_1_0 2024-07-20 17:59:30 +09:00
ToruNiina
098569a96d Merge branch 'main' into v4_1_0 2024-07-20 17:57:05 +09:00
ToruNiina
43f5a74bf0 feat: support string_type in toml::format 2024-07-20 17:23:05 +09:00
ToruNiina
6085c53ea2 fix: skip null char in string literal 2024-07-20 17:21:56 +09:00
Toru Niina
496782b42e Merge pull request #256 from CDK6182CHR/main
Support template into_toml members (Issue #255)
2024-07-20 16:20:24 +09:00
ToruNiina
f7deb1e89e feat [skip ci]: update single_include 2024-07-20 03:15:58 +00:00
xep
ce42e78e3c add test for template into_toml 2024-07-20 11:15:30 +08:00
xep
b853860a8f Add: template-version into_toml (Github issue #255) 2024-07-20 10:44:45 +08:00
ToruNiina
eba1aa2fde feat: take string type itself when conversion 2024-07-20 04:36:32 +09:00
ToruNiina
8434a6b18b Merge branch 'u8string' into v4_1_0 2024-07-18 01:03:58 +09:00
ToruNiina
eefca6e080 Merge branch 'main' into v4_1_0 2024-07-18 01:03:43 +09:00
ToruNiina
5e05b75473 test: add u8string constructor 2024-07-17 01:04:10 +09:00
ToruNiina
d9449747f3 fix: add constraint to array-like/table-like 2024-07-17 01:03:47 +09:00
ToruNiina
00e0ce12e7 feat: generalize ctor and remove feature macro 2024-07-16 23:48:15 +09:00
ToruNiina
92c2af024c feat: Merge branch 'ci-use-j' 2024-07-16 22:44:54 +09:00
ToruNiina
c9574b8ce6 ci: add cpu-cores and -j 2024-07-16 01:17:43 +09:00
ToruNiina
b68f1fd57f test: add case of get/find<u8string> 2024-07-16 01:03:19 +09:00
ToruNiina
d99f260c1a Merge branch 'origin/output-operator' into v4_1_0 2024-07-16 00:31:20 +09:00
ToruNiina
c0a8b60a5d feat: enable to convert generic string 2024-07-16 00:17:18 +09:00
ToruNiina
93503e9c59 fix: remove operator<<(basic_value) from test 2024-07-14 17:08:44 +09:00
ToruNiina
cae5f34fb1 doc: add int_fmt.uppercase to doc 2024-07-14 15:17:15 +09:00
ToruNiina
a69877005d test: check if uppercase is parsed 2024-07-14 15:14:01 +09:00
ToruNiina
452f1702c2 test: enable to output int_fmt.uppercase 2024-07-14 15:13:34 +09:00
ToruNiina
0f0f9cf3c1 feat: set upper/lowercase while serialization 2024-07-14 15:12:34 +09:00
ToruNiina
49b373d4f5 feat: parse hex int upper/lowercase 2024-07-14 15:12:18 +09:00
ToruNiina
acd6ed9a1e feat: add uppercase to integer fmt
for hex integer
2024-07-14 15:11:05 +09:00
ToruNiina
654ec0e013 feat: add stream operator to value 2024-07-14 14:20:04 +09:00
ToruNiina
9fd24aa23b feat [skip ci]: update single_include 2024-07-10 15:17:11 +00:00
Toru Niina
d8d325741c Merge pull request #253 from andreaskeller96/fix/correctly-resolve-carriage-return
Fix not checking for \r\n when parsing line comments
2024-07-11 00:06:43 +09:00
ToruNiina
f86d04f64d fix: toml::get<array-like> avoid u8string 2024-07-10 02:42:25 +09:00
ToruNiina
b78a37c826 feat: add u8string ctor 2024-07-10 02:39:51 +09:00
ToruNiina
29fbb6b695 feat: enable to convert key char type 2024-07-10 02:39:04 +09:00
ToruNiina
31810136d1 feat: generalize string converter 2024-07-10 02:37:29 +09:00
ToruNiina
a77516a2d0 feat: add string converter 2024-07-10 02:22:50 +09:00
ToruNiina
826e6414a0 feat: add detail::is_std_basic_string
to check if type T is a kind of std::basic_string<Char,...>
2024-07-10 02:04:31 +09:00
Andreas Keller
143437d309 Fix not checking for \\r\\n when parsing line comments 2024-07-09 09:50:31 +02:00
ToruNiina
5ac47b8983 chore: bump version to 4.0.3 2024-07-06 18:59:31 +09:00
ToruNiina
34a2091a4d doc: update README 2024-07-06 18:58:50 +09:00
ToruNiina
2e108e7010 feat [skip ci]: update single_include 2024-07-06 06:02:50 +00:00
ToruNiina
43c9c95de8 chore: avoid cmake compatibility warning 2024-07-06 14:48:55 +09:00
ToruNiina
9b41f4ab00 ci [skip actions]: trying to set newer SDK
to avoid warnings
2024-07-06 03:39:00 +09:00
ToruNiina
ed1604ca58 fix: ignore argument for NDEBUG build 2024-07-06 03:38:25 +09:00
ToruNiina
2c1269b82a ci: re-activate gcc/clang build 2024-07-06 02:38:07 +09:00
ToruNiina
ab94fbb2de feat [skip ci]: update single_include 2024-07-05 17:37:32 +00:00
ToruNiina
7ba94b37ab feat: merge branch 'add-werror' 2024-07-06 02:36:50 +09:00
ToruNiina
b2ea268d69 fix: unreachable code 2024-07-06 02:30:09 +09:00
ToruNiina
2912407d33 ci: temporary suppress gcc/clang 2024-07-06 02:29:56 +09:00
ToruNiina
b63668c0dc chore: raise msvc warning level 2024-07-06 02:14:24 +09:00
ToruNiina
d72493a2fc fix: remove name of unused argument 2024-07-06 01:37:11 +09:00
ToruNiina
58ddb8f589 doc: fix reference for the latest hugo ver 2024-07-06 01:31:20 +09:00
ToruNiina
9e194ea8b6 chore: add -Werror and while compilation 2024-07-06 01:13:32 +09:00
ToruNiina
be7d7257c9 feat [skip ci]: update single_include 2024-07-05 15:41:19 +00:00
ToruNiina
0eb9a90abf refactor: move HAS_CHAR8_T to version.hpp 2024-07-05 23:40:16 +09:00
ToruNiina
0cc0ef959b fix: directly access to member if type is the same 2024-07-05 23:32:00 +09:00
42 changed files with 2368 additions and 926 deletions

View File

@@ -11,6 +11,9 @@ jobs:
standard: ['11', '14', '17', '20']
precompile: ['ON', 'OFF']
steps:
- name: Get number of CPU cores
uses: SimenB/github-actions-cpu-cores@v2
id: cpu-cores
- name: Checkout
uses: actions/checkout@v4
with:
@@ -25,7 +28,7 @@ jobs:
cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build build/
cmake --build build/ -j${{ steps.cpu-cores.outputs.count }}
- name: Test
run: |
ctest --output-on-failure --test-dir build/
@@ -56,7 +59,7 @@ jobs:
cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build build/
cmake --build build/ -j${{ steps.cpu-cores.outputs.count }}
- name: Test
run: |
ctest --output-on-failure --test-dir build/
@@ -86,7 +89,7 @@ jobs:
cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build build/
cmake --build build/ -j${{ steps.cpu-cores.outputs.count }}
- name: Test
run: |
ctest --output-on-failure --test-dir build/
@@ -118,7 +121,7 @@ jobs:
cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build build/
cmake --build build/ -j${{ steps.cpu-cores.outputs.count }}
- name: Test
run: |
ctest --output-on-failure --test-dir build/
@@ -139,7 +142,7 @@ jobs:
cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build build/
cmake --build build/ -j${{ steps.cpu-cores.outputs.count }}
- name: Test
run: |
ctest --output-on-failure --test-dir build/
@@ -160,7 +163,7 @@ jobs:
cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build build/
cmake --build build/ -j${{ steps.cpu-cores.outputs.count }}
- name: Test
run: |
ctest --output-on-failure --test-dir build/
@@ -184,7 +187,7 @@ jobs:
cmake -B build/ -G "NMake Makefiles" -DTOML11_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_PRECOMPILE=${{ matrix.precompile }}
- name: Build
run: |
cmake --build ./build --config "${{ matrix.config }}"
cmake --build ./build --config "${{ matrix.config }}" -j${{ steps.cpu-cores.outputs.count }}
- name: Test
run: |
ctest --build-config "${{ matrix.config }}" --test-dir build/ --output-on-failure

View File

@@ -14,11 +14,13 @@ string(REGEX REPLACE "#define TOML11_VERSION_PATCH ([0-9]+)" "\\1" TOML11_VERSIO
project(toml11 LANGUAGES CXX VERSION "${TOML11_VERSION_MAJOR}.${TOML11_VERSION_MINOR}.${TOML11_VERSION_PATCH}")
include(CMakeDependentOption)
include(CTest)
include(CTest) # to use ${BUILD_TESTING}
option(TOML11_PRECOMPILE "precompile toml11 library" OFF)
include(CMakeDependentOption)
cmake_policy(PUSH)
cmake_policy(SET CMP0127 OLD) # syntax of condition changed in 3.22
cmake_dependent_option(TOML11_INSTALL "install toml11 library" ON
"${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}" OFF)
cmake_dependent_option(TOML11_BUILD_EXAMPLES "build toml11 examples" OFF
@@ -27,6 +29,8 @@ cmake_dependent_option(TOML11_BUILD_TESTS "build toml11 unit tests" OFF
"${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}; ${BUILD_TESTING}" OFF)
cmake_dependent_option(TOML11_BUILD_TOML_TESTS "build toml11 toml-test encoder & decoder" OFF
"${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}" OFF)
cmake_policy(POP)
cmake_dependent_option(TOML11_TEST_WITH_ASAN "build toml11 unit tests with asan" OFF
"${TOML11_BUILD_TESTS}" OFF)
cmake_dependent_option(TOML11_TEST_WITH_UBSAN "build toml11 unit tests with ubsan" OFF
@@ -36,8 +40,22 @@ if(${TOML11_TEST_WITH_ASAN} AND ${TOML11_TEST_WITH_UBSAN})
message(FATAL_ERROR "trying to build tests with BOTH asan and ubsan")
endif()
include(GNUInstallDirs)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-Wall" TOML11_COMPILER_SUPPORTS_WALL)
check_cxx_compiler_flag("-Wextra" TOML11_COMPILER_SUPPORTS_WEXTRA)
check_cxx_compiler_flag("-Wpedantic" TOML11_COMPILER_SUPPORTS_WPEDANTIC)
check_cxx_compiler_flag("-Werror" TOML11_COMPILER_SUPPORTS_WERROR)
check_cxx_compiler_flag("-Wsign-conversion" TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION)
check_cxx_compiler_flag("-Wconversion" TOML11_COMPILER_SUPPORTS_WCONVERSION)
check_cxx_compiler_flag("-Wduplicated-cond" TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND)
check_cxx_compiler_flag("-Wduplicated-branches" TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
check_cxx_compiler_flag("-Wlogical-op" TOML11_COMPILER_SUPPORTS_WLOGICAL_OP)
check_cxx_compiler_flag("-Wdouble-promotion" TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
check_cxx_compiler_flag("-Wrange-loop-analysis" TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
check_cxx_compiler_flag("-Wundef" TOML11_COMPILER_SUPPORTS_WUNDEF)
check_cxx_compiler_flag("-Wshadow" TOML11_COMPILER_SUPPORTS_WSHADOW)
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)

191
README.md
View File

@@ -100,6 +100,36 @@ Copy `single_include/toml.hpp` to your preferred location and add it to your inc
By adding toml11 as a subdirectory using `git submodule` (or any other way),
you can either add `toml11/include` to your include path or use `add_subdirectory(toml11)` in your CMake project.
### CMake `FetchContent`
Using `FetchContent`, you can automatically download it.
```cmake
include(FetchContent)
FetchContent_Declare(
toml11
GIT_REPOSITORY https://github.com/ToruNiina/toml11.git
GIT_TAG v4.1.0
)
FetchContent_MakeAvailable(toml11)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE toml11::toml11)
```
### CMake Package Manager (CPM)
After [adding cpm to your project](https://github.com/cpm-cmake/CPM.cmake?tab=readme-ov-file#adding-cpm), you can use toml11 by doing:
```cmake
include(cmake/CPM.cmake)
CPMAddPackage("gh:ToruNiina/toml11@4.1.0")
add_executable(main main.cpp)
target_link_libraries(main PUBLIC toml11::toml11)
```
### Install Using CMake
You can install toml11 using CMake with the following steps:
@@ -175,8 +205,30 @@ To parse a string directly, use `toml::parse_str`.
const toml::value input = toml::parse_str("a = 42");
```
`toml::parse` throws a `toml::syntax_error` exception on syntax errors.
To avoid this, use `toml::try_parse`, which returns a `toml::result`.
When parsing string literals, you can use the `""_toml` literal.
```cpp
using namespace toml::literals::toml_literals;
const toml::value lit = "a = 42"_toml;
```
`toml::parse`, `parse_str` and `_toml` literal throw a `toml::syntax_error` exception in case of a syntax error.
The error message obtained with `what()` will look like this:
```
[error] bad integer: `_` must be surrounded by digits
--> internal string at line 64 in file main.cpp
|
1 | a = 123__456
| ^-- invalid underscore
Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755
Hint: invalid: _42, 1__000, 0123
```
Error messages can also be colorized by calling `toml::color::enable()`.
By using `toml::try_parse`, you can receive a `toml::result<toml::value, std::vector<toml::error_info>>` without throwing exceptions.
```cpp
const auto input = toml::try_parse("input.toml");
@@ -227,6 +279,40 @@ const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a") << std::endl;
```
If type conversion or value lookup fails, a `toml::type_error` is thrown. The error message will look like this:
```
[error] toml::value::as_string(): bad_cast to string
--> input.toml
|
1 | a = 123_456
| ^^^^^^^-- the actual type is integer
```
You can access nested tables or arrays of tables in the same way.
```cpp
// [a]
// b = [
// {c = 42},
// {c = 54}
// ]
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a", "b", 1, "c") << std::endl;
```
Most STL containers and those with similar interfaces can be converted.
```cpp
// array = [3,1,4,1,5]
const toml::value input = toml::parse("input.toml");
const auto a1 = toml::find<std::vector<int>>(input, "array");
const auto a2 = toml::find<std::array<int, 5>>(input, "array");
const auto a3 = toml::find<std::deque<int>>(input, "array");
const auto a4 = toml::find<boost::container::small_vector<int, 8>>(input, "array");
```
You can perform advanced type conversions on complex TOML values.
```toml
@@ -245,6 +331,36 @@ const auto mixed = toml::find<
>(input, "mixed_array") << std::endl;
```
User-defined types can also be converted by using macros or defining some specific functions.
```cpp
namespace extlib
{
struct foo
{
int a;
std::string b;
};
} // extlib
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib::foo, a, b)
// ...
const auto input = R"(
[foo]
a = 42
b = "bar"
)"_toml;
const extlib::foo f = toml::find<extlib::foo>(input, "foo");
```
Using `toml::find_or`, you can get a default value in case of failure.
```cpp
const toml::value input = toml::parse("input.toml");
std::cout << toml::find_or(input, "a", 6*9) << std::endl;
```
For more details, please refer to the [documentation](https://toruniina.github.io/toml11/docs/features/value/).
### comments
@@ -331,19 +447,72 @@ std::cout << toml::format(input) << std::endl;
```cpp
toml::value output(toml::table{ {"a", 0xDEADBEEF} });
output.at("a").as_integer_fmt().fmt = toml::integer_format::hex;
output.at("a").as_integer_fmt().spacer = 4;
output.at("a").as_integer_fmt().spacer = 4; // position of `_`
std::cout << toml::format(input) << std::endl;
// a = 0xdead_beef
```
You can also specify the formatting for tables and arrays.
```cpp
toml::value output(toml::table{
{"array-of-tables", toml::array{}},
{"subtable", toml::table{}},
});
auto& aot = output.at("array-of-tables");
aot.as_array_fmt().fmt = toml::array_format::multiline; // one element per line
aot.as_array_fmt().body_indent = 4;
aot.as_array_fmt().closing_indent = 2;
toml::value v1(toml::table{ {"a", 42}, {"b", 3.14} });
v1.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v1));
toml::value v2(toml::table{ {"a", 42}, {"b", 3.14} });
v2.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v2));
output.at("subtable").as_table_fmt().fmt = toml::table_format::dotted;
output.at("subtable")["a"] = 42;
output.at("subtable")["b"] = 3.14;
std::cout << toml::format(output) << std::endl;
// subtable.b = 3.14
// subtable.a = 42
// array-of-tables = [
// {b = 3.14, a = 42},
// {b = 3.14, a = 42},
// ]
```
These settings are read during parsing and will be maintained as long as the value type does not change when modified.
For details on possible formatting specifications, please refer to the [documentation](https://toruniina.github.io/toml11/docs/features/serialize/).
### configuring types
### Configuring Types
[The examples directory](https://github.com/ToruNiina/toml11/tree/main/examples) provides usage examples, such as using
arbitrary-precision integers, normalizing Unicode, and integrating with an external reflection library.
Many types held by `toml::value`, such as `integer_type` and `array_type`, can be modified by changing the `type_config` type.
Please refer to these examples for implementation guidance in such scenarios.
Refer to the [`examples` directory](https://github.com/ToruNiina/toml11/tree/main/examples) for complex use cases such as using multi-precision integers, changing containers, and normalizing Unicode.
Use these examples as references for implementing such configurations.
## Examples
The [`examples`](https://github.com/ToruNiina/toml11/tree/main/examples) directory provides various implementation examples in addition to type configurations.
- [boost_container](https://github.com/ToruNiina/toml11/tree/main/examples/boost_container)
- This example shows how to use `boost::container` containers for `array_type` and `table_type`.
- [boost_multiprecision](https://github.com/ToruNiina/toml11/tree/main/examples/boost_multiprecision)
- This example demonstrates the use of `boost::multiprecision` multi-precision numeric types for `integer_type` and `floating_type`.
- [parse_file](https://github.com/ToruNiina/toml11/tree/main/examples/parse_file)
- This example includes type conversion implementations, covering slightly more complex cases. The corresponding TOML file is included.
- [reflect](https://github.com/ToruNiina/toml11/tree/main/examples/reflect)
- This example shows self-type conversion using boost-ext/reflect for user-defined types.
- [unicode](https://github.com/ToruNiina/toml11/tree/main/examples/unicode)
- This example demonstrates normalizing Unicode strings when searching for keys using uni-algo.
## Changes from v3
@@ -467,6 +636,14 @@ I appreciate the help of the contributors who introduced the great feature to th
- Add fuzzing test based on ClusterFuzzLite
- Esonhugh Skyworship (@Esonhugh)
- Fix function signature of `strerror_r` on macos
- Alberto (@0X1A)
- Fix issues with CMake package configuration when used with vcpkg
- Egor Pugin (@egorpugin)
- Fix incorrect operator<<() argument type that gives build error
- Andreas Keller (@andreaskeller96)
- Fix not checking for \r\n when parsing line comments
- 萧迩珀 (@CDK6182CHR)
- Support template into_toml members
## Licensing terms

View File

@@ -97,6 +97,36 @@ toml11を使うには複数の方法があります。
git submoduleなどでサブディレクトリにすれば、`toml11/include`にインクルードパスを通すか、
`add_subdirectory(toml11)` とすることで使用できます。
### CMake `FetchContent`
CMakeの `FetchContent`を使用することで、`build`ディレクトリに自動でダウンロードすることができます。
```cmake
include(FetchContent)
FetchContent_Declare(
toml11
GIT_REPOSITORY https://github.com/ToruNiina/toml11.git
GIT_TAG v4.0.3
)
FetchContent_MakeAvailable(toml11)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE toml11::toml11)
```
### CMake Package Manager (CPM)
[CMake package manager](https://github.com/cpm-cmake/CPM.cmake)を導入すると、以下のようにして使用することができます。
```cmake
include(cmake/CPM.cmake)
CPMAddPackage("gh:ToruNiina/toml11@4.1.0")
add_executable(main main.cpp)
target_link_libraries(main PUBLIC toml11::toml11)
```
### Install using CMake
以下の手順で、CMakeを使ってインストールすることができます。
@@ -139,7 +169,7 @@ $ cmake -B ./build/ -DTOML11_BUILD_EXAMPLES=ON
$ cmake --build ./build/
```
### Building example
### Building Tests
`-DTOML11_BUILD_TESTS=ON`とすることで、ユニットテストをコンパイルできます。
@@ -174,8 +204,30 @@ const toml::value input = toml::parse("input.toml");
const toml::value input = toml::parse_str("a = 42");
```
`toml::parse`は文法エラーの際に `toml::syntax_error` 例外を投げます。
これを避けるには、 `toml::result` を返す `toml::try_parse` を使います。
文字列リテラルをパースする際は、`""_toml`リテラルを使うことができます。
```cpp
using namespace toml::literals::toml_literals;
const toml::value lit = "a = 42"_toml;
```
`toml::parse``parse_str`は文法エラーの際に `toml::syntax_error` 例外を投げます。
`what()`で得られるエラーメッセージは以下のようになります。
```
[error] bad integer: `_` must be surrounded by digits
--> internal string at line 64 in file main.cpp
|
1 | a = 123__456
| ^-- invalid underscore
Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755
Hint: invalid: _42, 1__000, 0123
```
エラーメッセージには`toml::color::enable()`を呼ぶことで色を付けることも可能です。
`toml::try_parse`を使うことで、例外を投げずに `toml::result<toml::value, std::vector<toml::error_info>>` を受け取ることができます。
```cpp
const auto input = toml::try_parse("input.toml");
@@ -219,11 +271,46 @@ if(input.contains("a") && input.at("a").is_integer())
}
```
`toml::find` を使うことで、型変換と検索同時に行ます。
`toml::find` を使うことで、型変換と検索同時に行うことができます。
```cpp
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a") << std::endl;
std::cout << toml::find<std::string>(input, "a") << std::endl;
```
型変換や値の検索に失敗した場合は、`toml::type_error`が送出されます。
その場合のエラーメッセージは以下のようになります。
```
[error] toml::value::as_string(): bad_cast to string
--> input.toml
|
1 | a = 123_456
| ^^^^^^^-- the actual type is integer
```
ネストされたテーブルやテーブルの配列にも同じ方法でアクセスできます。
```cpp
// [a]
// b = [
// {c = 42},
// {c = 54}
// ]
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a", "b", 1, "c") << std::endl;
```
ほとんどのSTLコンテナや、同様のインターフェースを持つコンテナへ変換が可能です。
```cpp
// array = [3,1,4,1,5]
const toml::value input = toml::parse("input.toml");
const auto a1 = toml::find<std::vector<int> >(input, "array") << std::endl;
const auto a2 = toml::find<std::array<int, 5>>(input, "array") << std::endl;
const auto a3 = toml::find<std::deque<int> >(input, "array") << std::endl;
const auto a4 = toml::find<boost::container::small_vector<int, 8>>(input, "array") << std::endl;
```
また、複雑なTOML値に対して、高度な型変換を行うことができます。
@@ -244,6 +331,36 @@ const auto mixed = toml::find<
>(input, "mixed_array") << std::endl;
```
マクロの使用または特定の関数を定義することで、ユーザー定義型にも変換が可能です。
```cpp
namespace extlib
{
struct foo
{
int a;
std::string b;
};
} // extlib
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib::foo, a, b)
// ...
const auto input = R"(
[foo]
a = 42
b = "bar"
)"_toml;
const extlib::foo f = toml::find<extlib::foo>(input, "foo");
```
`toml::find_or`を使うことで、失敗時にデフォルト値を得ることができます。
```cpp
const toml::value input = toml::parse("input.toml");
std::cout << toml::find_or(input, "a", 6*9) << std::endl;
```
詳細については[ドキュメント](https://toruniina.github.io/toml11/ja/docs/features/value/)を参照してください。
### comments
@@ -332,18 +449,73 @@ toml::value output(toml::table{ {"a", 0xDEADBEEF} });
output.at("a").as_integer_fmt().fmt = toml::integer_format::hex;
output.at("a").as_integer_fmt().spacer = 4;
std::cout << toml::format(input) << std::endl;
std::cout << toml::format(output) << std::endl;
// a = 0xdead_beef
```
テーブルや配列のフォーマットも指定が可能です。
```cpp
toml::value output(toml::table{
{"array-of-tables", toml::array{}},
{"subtable", toml::table{}},
});
auto& aot = output.at("array-of-tables");
aot.as_array_fmt().fmt = toml::array_format::multiline;
aot.as_array_fmt().body_indent = 4;
aot.as_array_fmt().closing_indent = 2;
toml::value v1(toml::table{ {"a", 42}, {"b", 3.14} });
v1.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v1));
toml::value v2(toml::table{ {"a", 42}, {"b", 3.14} });
v2.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v2));
output.at("subtable").as_table_fmt().fmt = toml::table_format::dotted;
output.at("subtable")["a"] = 42;
output.at("subtable")["b"] = 3.14;
std::cout << toml::format(output) << std::endl;
// subtable.b = 3.14
// subtable.a = 42
// array-of-tables = [
// {b = 3.14, a = 42},
// {b = 2.71, a = 54},
// ]
```
これらの設定はパース時に読み取られ、値を変更した際も型が変わらない限り維持されます。
どのような指定が可能かなどの詳細は[ドキュメント](https://toruniina.github.io/toml11/ja/docs/features/serialize/)を参照してください。
### configuring types
[`examples`ディレクトリ](https://github.com/ToruNiina/toml11/tree/main/examples)には、多倍長整数を使用する場合やユニコードを正規化する場合、
外部のリフレクションライブラリと連携する場合などの複雑な使用例を用意しています。
`toml::value`が持つ型の多く、`integer_type``array_type`などは`type_config`型を変更することで変更可能です。
[`examples`ディレクトリ](https://github.com/ToruNiina/toml11/tree/main/examples)には、
多倍長整数を使用する場合やコンテナを変更する場合、ユニコードを正規化する場合などの複雑な使用例を用意しています。
そのような状況での実装例として参照してください。
## Examples
[`examples`ディレクトリ](https://github.com/ToruNiina/toml11/tree/main/examples)では、
型の設定の他にも実装例を紹介しています。
- [boost_container](https://github.com/ToruNiina/toml11/tree/main/examples/boost_container)
- `array_type``table_type``boost::container`のコンテナを使う例です。
- [boost_multiprecision](https://github.com/ToruNiina/toml11/tree/main/examples/boost_multiprecision)
- `integer_type``floating_type``boost::multiprecision`の多倍長数値型を使う例です。
- [parse_file](https://github.com/ToruNiina/toml11/tree/main/examples/parse_file)
- 少し複雑な場合も含めた、型変換の実装例です。対応するTOMLファイルが同梱されています。
- [reflect](https://github.com/ToruNiina/toml11/tree/main/examples/reflect)
- boost-ext/reflectを用いたユーザー定義型との自型変換の例です。
- [unicode](https://github.com/ToruNiina/toml11/tree/main/examples/unicode)
- uni-algoを用いて、キーを検索する際にユニコード文字列を正規化する例です。
## Changes from v3
toml11 v3からは複数の破壊的変更が追加されています。
@@ -466,6 +638,14 @@ toml11 v3からは複数の破壊的変更が追加されています。
- Add fuzzing test based on ClusterFuzzLite
- Esonhugh Skyworship (@Esonhugh)
- Fix function signature of `strerror_r` on macos
- Alberto (@0X1A)
- Fix issues with CMake package configuration when used with vcpkg
- Egor Pugin (@egorpugin)
- Fix incorrect operator<<() argument type that gives build error
- Andreas Keller (@andreaskeller96)
- Fix not checking for \r\n when parsing line comments
- 萧迩珀 (@CDK6182CHR)
- Support template into_toml members
## Licensing terms

View File

@@ -4,8 +4,10 @@ environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
generator: Visual Studio 16 2019
systemver: 10.0.18362.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
generator: Visual Studio 17 2022
systemver: 10.0.22621.0
configuration:
- Release
@@ -19,7 +21,7 @@ install:
build_script:
- cd C:\toml11
- cmake -B build -G"%generator%" -A x64 -DCMAKE_CXX_STANDARD=11 -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=ON
- cmake -B build -G"%generator%" -DCMAKE_SYSTEM_VERSION="%systemver%" -A x64 -DCMAKE_CXX_STANDARD=11 -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=ON
- cmake --build build --config "%configuration%"
test_script:

View File

@@ -7,19 +7,19 @@ type = "docs"
日本語版は[こちら](/toml11/ja/)
## [Installation]({{< relref "/installation" >}})
## [Installation](docs/installation)
This section describes how to build and install toml11.
## [Features]({{< relref "/features" >}})
## [Features](docs/features)
This section describes how to use toml11's features with examples.
## [Reference]({{< relref "/reference" >}})
## [Reference](docs/reference)
This section details toml11 functions and classes.
## [ChangeLog]({{< relref "/changelog" >}})
## [ChangeLog](docs/changelog)
This section describes changes from release to release.

View File

@@ -6,12 +6,60 @@ weight = 4
# Change Log
# v4.1.0
## Added
- support `std::get<std::u8string>`
- support `toml::value(std::u8string)`
- support `string_type = std::u8string`
- support `operator<<(std::ostream&, toml::value)`
- add `bool uppercase` to `toml::integer_format`
- support `template into_toml()` (by 萧迩珀)
## Fixed
- Fix not checking for `\r\n` when parsing line comments (by Andreas Keller)
## Changed
- speedup CI tests by multicore build
# v4.0.3
## Fixed
- remove default template argument from forward declaration in `toml_fwd.hpp`
- enable to call `toml::make_error_info` with multiple `toml::value`s
- enable to copy/move `toml::result` having `std::reference_wrapper`
- fix document generation error with the latest version of hugo
- fix several tiny errors that causes warning
- fix CMake compatibility warning
## Changed
add `-Werror` / `/WX` to build script
set MSVC warning level to `/W4`
add explanation of features to README
# v4.0.2
## Fixed
- check return value of fread in `parse(FILE*)`
- version macro defined in `toml11/version.hpp`
- update docs about compilation
- update docs about file open mode
## Changed
- use version macros defined in `toml11/version.hpp` as the project version in `CMakeLists.txt`
# v4.0.1
## Fixed
- Resolved naming conflict of `sematic_version::{major, minor}` with macros defined in `<sys/sysmacro.h>`
- Fixed the definition of `operator<<` in `discard_comments`
- Fixed the definition of `operator<<` in `discard_comments` (by Egor Pugin)
- Fixed the issue where the first blank line was not output in `format_location`
- Fixed the issue where error messages pointing to `source_location` referring to lines containing only newline characters were displayed in two lines
- Corrected links in the README

View File

@@ -60,10 +60,11 @@ Specifies the radix of an `integer`.
```cpp
struct integer_format_info
{
integer_format fmt = integer_format::dec;
std::size_t width = 0; // minimal width (may exceed)
std::size_t spacer = 0; // position of `_` (if 0, no spacer)
std::string suffix = ""; // _suffix (library extension)
integer_format fmt = integer_format::dec;
bool uppercase = true; // use uppercase letters
std::size_t width = 0; // minimal width (may exceed)
std::size_t spacer = 0; // position of `_` (if 0, no spacer)
std::string suffix = ""; // _suffix (library extension)
};
bool operator==(const integer_format_info&, const integer_format_info&) noexcept;
@@ -76,6 +77,10 @@ bool operator!=(const integer_format_info&, const integer_format_info&) noexcept
Specifies the radix.
### `bool uppercase`
Uses uppercase letters when formatted as a hexadecimal integer.
### `std::size_t width`
Specifies the minimum width. The formatted value may exceed this width.

View File

@@ -7,19 +7,19 @@ type = "docs"
English version is [here](../en/)
## [Installation]({{< relref "/installation" >}})
## [Installation](docs/installation)
toml11のインストール方法について説明します。
## [Features]({{< relref "/features" >}})
## [Features](docs/features)
toml11の機能と使い方を例に沿って説明します。
## [Reference]({{< relref "/reference" >}})
## [Reference](docs/reference)
toml11が持つ関数・クラスの詳細を説明します。
## [ChangeLog]({{< relref "/changelog" >}})
## [ChangeLog](docs/changelog)
v3系から、そしてリリースごとの変化を説明します。

View File

@@ -6,12 +6,61 @@ weight = 4
# Change Log
# v4.1.0
## Added
- `std::get<std::u8string>`をサポート
- `toml::value(std::u8string)`をサポート
- `string_type = std::u8string`をサポート
- `operator<<(std::ostream&, toml::value)`をサポート
- `toml::integer_format`に、16進数表示で大文字を使うことを指定する`bool uppercase`を追加
- `template`を使って実装された `into_toml()` をサポート (by 萧迩珀)
## Fixed
- Windowsで`\r\n`が改行に使われた際、出力時に`\r`が重複する問題を修正 (by Andreas Keller)
## Changed
- CIで複数コアを使うことでビルドを高速化
# v4.0.3
## Fixed
- `toml_fwd.hpp`を使用した際にデフォルト引数が重複する問題を修正
- `toml::value`を複数渡した際に`toml::make_error_info`が使えない問題を修正
- `std::reference_wrapper`を持つ`toml::result`をコピー・ムーブする際の問題を修正
- hugoの最新版でドキュメントがビルドできない問題を修正
- コンパイラによる軽微な警告を多数修正
- CMakeの互換性に関する警告を抑制
## Changed
- CIビルドで`-Werror`, `/WX`を追加
- CIビルドでMSVCのwarningレベルを`/W3`から`/W4`に変更
- READMEでより多くの機能を紹介するよう更新
# v4.0.2
## Fixed
- `parse(FILE*)` 内の `fread` の結果をチェック
- `toml11/version.hpp`のマクロを修正
- コンパイルオプションに関するドキュメントの更新
- ファイルオープンモードに関するドキュメントの更新
## Changed
- `CMakeLists.txt`内のバージョン番号を`version.hpp`から取得するように変更
# v4.0.1
## Fixed
- `sematic_version::{major, minor}``<sys/sysmacro.h>` 内で定義されるマクロの衝突を解消
- `discard_comments``operator<<` の定義を修正
- `discard_comments``operator<<` の定義を修正 (by Egor Pugin)
- `format_location`を使用した際に最初の空行が出ない問題を解決
- 改行文字のみを含む行を指す`source_location`でエラーメッセージを生成した際に、同じ行が二回表示される問題を解決
- `README.md`内のリンクを修正

View File

@@ -60,10 +60,11 @@ std::string to_string(const integer_format);
```cpp
struct integer_format_info
{
integer_format fmt = integer_format::dec;
std::size_t width = 0; // minimal width (may exceed)
std::size_t spacer = 0; // position of `_` (if 0, no spacer)
std::string suffix = ""; // _suffix (library extension)
integer_format fmt = integer_format::dec;
bool uppercase = true; // use uppercase letters
std::size_t width = 0; // minimal width (may exceed)
std::size_t spacer = 0; // position of `_` (if 0, no spacer)
std::string suffix = ""; // _suffix (library extension)
};
bool operator==(const integer_format_info&, const integer_format_info&) noexcept;
@@ -76,6 +77,10 @@ bool operator!=(const integer_format_info&, const integer_format_info&) noexcept
基数を指定します。
### `bool uppercase`
16進数表記で大文字を使用します。
### `std::size_t width`
最小の幅を指定します。値によってはこの幅を超えることがあります。

View File

@@ -2,4 +2,5 @@ add_subdirectory(boost_container)
add_subdirectory(boost_multiprecision)
add_subdirectory(parse_file)
add_subdirectory(reflect)
add_subdirectory(u8string)
add_subdirectory(unicode)

1
examples/u8string/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
u8string

View File

@@ -0,0 +1,5 @@
add_executable(u8string u8string.cpp)
target_link_libraries(u8string PRIVATE toml11::toml11)
target_compile_features(u8string PRIVATE cxx_std_20)
set_target_properties(u8string PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")

View File

@@ -0,0 +1,23 @@
# This is a TOML document
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }
[servers]
[servers.alpha]
ip = "10.0.0.1"
role = "frontend"
[servers.beta]
ip = "10.0.0.2"
role = "backend"

View File

@@ -0,0 +1,120 @@
#include <toml.hpp>
#include <iostream>
#include <map>
#include <cassert>
struct u8config
{
using comment_type = toml::preserve_comments;
using boolean_type = bool;
using integer_type = std::int64_t;
using floating_type = double;
using string_type = std::u8string; // XXX
template<typename T>
using array_type = std::vector<T>;
template<typename K, typename T>
using table_type = std::unordered_map<K, T>;
static toml::result<integer_type, toml::error_info>
parse_int(const std::string& str, const toml::source_location src, const std::uint8_t base)
{
return toml::read_int<integer_type>(str, src, base);
}
static toml::result<floating_type, toml::error_info>
parse_float(const std::string& str, const toml::source_location src, const bool is_hex)
{
return toml::read_float<floating_type>(str, src, is_hex);
}
};
int main()
{
const auto root = toml::parse<u8config>("spec_example.toml");
// using member functions
{
assert(root.at(u8"title").as_string() == u8"TOML Example");
assert(root.at(u8"owner").at(u8"name").as_string() == u8"Tom Preston-Werner");
const auto dob = root.at(u8"owner").at(u8"dob" ).as_offset_datetime();
assert(dob.date .year == 1979);
assert(dob.date .month == static_cast<int>(toml::month_t::May));
assert(dob.date .day == 27);
assert(dob.time .hour == 7);
assert(dob.time .minute == 32);
assert(dob.time .second == 0);
assert(dob.offset.hour == -8);
assert(dob.offset.minute == 0);
assert(root.at(u8"database").at(u8"enabled").as_boolean());
assert(root.at(u8"database").at(u8"ports").at(0).as_integer() == 8000);
assert(root.at(u8"database").at(u8"ports").at(1).as_integer() == 8001);
assert(root.at(u8"database").at(u8"ports").at(2).as_integer() == 8002);
assert(root.at(u8"database").at(u8"data").at(0).at(0).as_string() == u8"delta");
assert(root.at(u8"database").at(u8"data").at(0).at(1).as_string() == u8"phi");
assert(root.at(u8"database").at(u8"data").at(1).at(0).as_floating() == 3.14);
assert(root.at(u8"database").at(u8"temp_targets").at(u8"cpu" ).as_floating() == 79.5);
assert(root.at(u8"database").at(u8"temp_targets").at(u8"case").as_floating() == 72.0);
assert(root.at(u8"servers").at(u8"alpha").at(u8"ip" ).as_string() == u8"10.0.0.1");
assert(root.at(u8"servers").at(u8"alpha").at(u8"role").as_string() == u8"frontend");
assert(root.at(u8"servers").at(u8"beta" ).at(u8"ip" ).as_string() == u8"10.0.0.2");
assert(root.at(u8"servers").at(u8"beta" ).at(u8"role").as_string() == u8"backend");
}
// using toml::find
{
// you can get as std::string from u8string, using toml::get/find
assert(toml::find<std::string>(root, u8"title") == "TOML Example");
assert(toml::find<std::string>(root, u8"owner", u8"name") == "Tom Preston-Werner");
const auto dob = toml::find<toml::offset_datetime>(root, u8"owner", u8"dob");
assert(dob.date .year == 1979);
assert(dob.date .month == static_cast<int>(toml::month_t::May));
assert(dob.date .day == 27);
assert(dob.time .hour == 7);
assert(dob.time .minute == 32);
assert(dob.time .second == 0);
assert(dob.offset.hour == -8);
assert(dob.offset.minute == 0);
assert(toml::find<bool>(root, u8"database", u8"enabled"));
const auto ports = toml::find<std::vector<int>>(root, u8"database", u8"ports");
assert(ports.at(0) == 8000);
assert(ports.at(1) == 8001);
assert(ports.at(2) == 8002);
const auto data = toml::find<std::pair<std::vector<std::string>, std::vector<double>>>(root, u8"database", u8"data");
assert(data.first.at(0) == "delta");
assert(data.first.at(1) == "phi");
assert(data.second.at(0) == 3.14);
const auto temp_targets = toml::find<std::map<std::string, double>>(root, u8"database", u8"temp_targets");
assert(temp_targets.at("cpu" ) == 79.5);
assert(temp_targets.at("case") == 72.0);
const auto servers = toml::find<std::map<std::string, std::map<std::string, std::string>>>(root, u8"servers");
assert(servers.at("alpha").at("ip" ) == "10.0.0.1");
assert(servers.at("alpha").at("role") == "frontend");
assert(servers.at("beta" ).at("ip" ) == "10.0.0.2");
assert(servers.at("beta" ).at("role") == "backend" );
}
const std::u8string out = toml::format(root);
std::string printable;
std::transform(out.begin(), out.end(), std::back_inserter(printable),
[](const char8_t c) {return static_cast<char>(c);});
std::cout << printable << std::endl;
std::cout << "ok." << std::endl;
return 0;
}

View File

@@ -498,7 +498,7 @@ struct source_location
static source_location current() { return source_location{}; }
};
inline std::string to_string(const source_location& loc)
inline std::string to_string(const source_location&)
{
return std::string("");
}

View File

@@ -57,9 +57,10 @@ std::string to_string(const integer_format);
struct integer_format_info
{
integer_format fmt = integer_format::dec;
std::size_t width = 0; // minimal width (may exceed)
std::size_t spacer = 0; // position of `_` (if 0, no spacer)
std::string suffix = ""; // _suffix (library extension)
bool uppercase = true; // hex with uppercase
std::size_t width = 0; // minimal width (may exceed)
std::size_t spacer = 0; // position of `_` (if 0, no spacer)
std::string suffix = ""; // _suffix (library extension)
};
bool operator==(const integer_format_info&, const integer_format_info&) noexcept;
@@ -213,6 +214,29 @@ struct table_format_info
bool operator==(const table_format_info&, const table_format_info&) noexcept;
bool operator!=(const table_format_info&, const table_format_info&) noexcept;
// ----------------------------------------------------------------------------
// key
enum class key_format : std::uint8_t
{
bare = 0,
quoted = 1, // ""
quoted_literal = 2 // ''
};
std::ostream& operator<<(std::ostream& os, const key_format f);
std::string to_string(const key_format);
struct key_format_info
{
key_format fmt = key_format::bare;
std::int32_t spaces_before_equal = 1;
std::int32_t spaces_after_equal = 1;
};
bool operator==(const key_format_info&, const key_format_info&) noexcept;
bool operator!=(const key_format_info&, const key_format_info&) noexcept;
// ----------------------------------------------------------------------------
// wrapper

View File

@@ -3,7 +3,7 @@
#include "../location.hpp"
#include "../types.hpp"
#include "../value.hpp"
#include "../version.hpp" // IWYU pragma: keep for TOML11_HAS_CHAR8_T
namespace toml
{
@@ -21,12 +21,6 @@ inline namespace toml_literals
::toml::value operator"" _toml(const char* str, std::size_t len);
#if defined(__cpp_char8_t)
# if __cpp_char8_t >= 201811L
# define TOML11_HAS_CHAR8_T 1
# endif
#endif
#if defined(TOML11_HAS_CHAR8_T)
// value of u8"" literal has been changed from char to char8_t and char8_t is
// NOT compatible to char

View File

@@ -109,16 +109,29 @@ get(const basic_value<TC>& v)
return static_cast<T>(v.as_floating());
}
// ============================================================================
// std::string with different char/trait/allocator
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_not_toml_type<T, basic_value<TC>>,
detail::is_1byte_std_basic_string<T>
>::value, T>
get(const basic_value<TC>& v)
{
return detail::string_conv<cxx::remove_cvref_t<T>>(v.as_string());
}
// ============================================================================
// std::string_view
#if defined(TOML11_HAS_STRING_VIEW)
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
cxx::enable_if_t<detail::is_string_view_of<T, typename basic_value<TC>::string_type>::value, T>
get(const basic_value<TC>& v)
{
return std::string_view(v.as_string());
return T(v.as_string());
}
#endif // string_view
@@ -175,6 +188,10 @@ cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>, // T is a container
detail::has_push_back_method<T>, // .push_back() works
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array
cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>
#if defined(TOML11_HAS_STRING_VIEW)
cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>
#endif
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
@@ -201,16 +218,33 @@ template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_tuple<T>::value, T>
get(const basic_value<TC>&);
// map-like
// std::map<key, value> (key is convertible from toml::value::key_type)
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>, // keys are convertible
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>&);
get(const basic_value<TC>& v);
// std::map<key, value> (key is not convertible from toml::value::key_type, but
// is a std::basic_string)
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
cxx::negation<std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>>, // keys are NOT convertible
detail::is_1byte_std_basic_string<typename T::key_type>, // is std::basic_string
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>& v);
// toml::from<T>::from_toml(v)
template<typename T, typename TC>
@@ -245,6 +279,10 @@ cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>, // T is a container
detail::has_push_back_method<T>, // .push_back() works
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array
cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>
#if defined(TOML11_HAS_STRING_VIEW)
cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>
#endif
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
@@ -363,10 +401,13 @@ get(const basic_value<TC>& v)
// ============================================================================
// map-like types; most likely STL map, like std::map or std::unordered_map.
// key is convertible from toml::value::key_type
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>, // keys are convertible
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
@@ -388,6 +429,31 @@ get(const basic_value<TC>& v)
return m;
}
// key is NOT convertible from toml::value::key_type but std::basic_string
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
cxx::negation<std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>>, // keys are NOT convertible
detail::is_1byte_std_basic_string<typename T::key_type>, // is std::basic_string
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>& v)
{
using key_type = typename T::key_type;
using mapped_type = typename T::mapped_type;
T m;
for(const auto& kv : v.as_table())
{
m.emplace(detail::string_conv<key_type>(kv.first), get<mapped_type>(kv.second));
}
return m;
}
// ============================================================================
// user-defined, but convertible types.

View File

@@ -66,10 +66,11 @@ TOML11_INLINE std::string to_string(const integer_format c)
TOML11_INLINE bool operator==(const integer_format_info& lhs, const integer_format_info& rhs) noexcept
{
return lhs.fmt == rhs.fmt &&
lhs.width == rhs.width &&
lhs.spacer == rhs.spacer &&
lhs.suffix == rhs.suffix ;
return lhs.fmt == rhs.fmt &&
lhs.uppercase == rhs.uppercase &&
lhs.width == rhs.width &&
lhs.spacer == rhs.spacer &&
lhs.suffix == rhs.suffix ;
}
TOML11_INLINE bool operator!=(const integer_format_info& lhs, const integer_format_info& rhs) noexcept
{
@@ -292,5 +293,41 @@ TOML11_INLINE bool operator!=(const table_format_info& lhs, const table_format_i
return !(lhs == rhs);
}
// ----------------------------------------------------------------------------
// key
TOML11_INLINE std::ostream& operator<<(std::ostream& os, const key_format f)
{
switch(f)
{
case key_format::bare : {os << "bare" ; break;}
case key_format::quoted : {os << "quoted" ; break;}
case key_format::quoted_literal : {os << "quoted_literal"; break;}
default:
{
os << "unknown key_format: " << static_cast<std::uint8_t>(f);
break;
}
}
return os;
}
TOML11_INLINE std::string to_string(const key_format c)
{
std::ostringstream oss;
oss << c;
return oss.str();
}
TOML11_INLINE bool operator==(const key_format_info& lhs, const key_format_info& rhs) noexcept
{
return lhs.fmt == rhs.fmt &&
lhs.spaces_before_equal == rhs.spaces_before_equal &&
lhs.spaces_after_equal == rhs.spaces_after_equal ;
}
TOML11_INLINE bool operator!=(const key_format_info& lhs, const key_format_info& rhs) noexcept
{
return !(lhs == rhs);
}
} // namespace toml
#endif // TOML11_FORMAT_IMPL_HPP

View File

@@ -552,6 +552,7 @@ TOML11_INLINE either string(const spec& s)
TOML11_INLINE non_ascii_key_char::non_ascii_key_char(const spec& s) noexcept
{
assert(s.v1_1_0_allow_non_english_in_bare_keys);
(void)s; // for NDEBUG
}
TOML11_INLINE std::uint32_t non_ascii_key_char::read_utf8(location& loc) const

View File

@@ -172,7 +172,7 @@ parse_boolean(location& loc, const context<TC>& ctx)
// no format info for boolean
boolean_format_info fmt;
return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val, std::move(fmt), {}, {}, std::move(reg)));
}
/* ============================================================================
@@ -221,7 +221,7 @@ parse_bin_integer(location& loc, const context<TC>& ctx)
const auto val = TC::parse_int(str, source_location(region(loc)), 2);
if(val.is_ok())
{
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, {}, std::move(reg)));
}
else
{
@@ -273,7 +273,7 @@ parse_oct_integer(location& loc, const context<TC>& ctx)
const auto val = TC::parse_int(str, source_location(region(loc)), 8);
if(val.is_ok())
{
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, {}, std::move(reg)));
}
else
{
@@ -292,7 +292,7 @@ parse_hex_integer(location& loc, const context<TC>& ctx)
if( ! reg.is_ok())
{
return err(make_syntax_error("toml::parse_hex_integer: "
"invalid integer: hex_int must be like: 0xC0FFEE, 0xDEAD_BEEF",
"invalid integer: hex_int must be like: 0xC0FFEE, 0xdead_beef",
syntax::hex_int(spec), loc));
}
@@ -320,10 +320,18 @@ parse_hex_integer(location& loc, const context<TC>& ctx)
// 0x0000_0000 becomes empty.
if(str.empty()) { str = "0"; }
// prefix zero and _ is removed. check if it uses upper/lower case.
// if both upper and lower case letters are found, set upper=true.
const auto lower_not_found = std::find_if(str.begin(), str.end(),
[](const char c) { return std::islower(static_cast<int>(c)) != 0; }) == str.end();
const auto upper_found = std::find_if(str.begin(), str.end(),
[](const char c) { return std::isupper(static_cast<int>(c)) != 0; }) != str.end();
fmt.uppercase = lower_not_found || upper_found;
const auto val = TC::parse_int(str, source_location(region(loc)), 16);
if(val.is_ok())
{
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, {}, std::move(reg)));
}
else
{
@@ -394,7 +402,7 @@ parse_dec_integer(location& loc, const context<TC>& ctx)
fmt.suffix = sfx;
}
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, {}, std::move(reg)));
}
template<typename TC>
@@ -659,7 +667,7 @@ parse_floating(location& loc, const context<TC>& ctx)
fmt.suffix = sfx;
}
return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val, std::move(fmt), {}, {}, std::move(reg)));
}
/* ============================================================================
@@ -777,7 +785,7 @@ parse_local_date(location& loc, const context<TC>& ctx)
auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap()));
auto reg = std::move(std::get<2>(val_fmt_reg.unwrap()));
return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, {}, std::move(reg)));
}
// all the offset_datetime, local_datetime, local_time parses date part.
@@ -946,7 +954,7 @@ parse_local_time(location& loc, const context<TC>& ctx)
auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap()));
auto reg = std::move(std::get<2>(val_fmt_reg.unwrap()));
return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, {}, std::move(reg)));
}
template<typename TC>
@@ -1005,7 +1013,7 @@ parse_local_datetime(location& loc, const context<TC>& ctx)
local_datetime val(std::get<0>(date_fmt_reg.unwrap()),
std::get<0>(time_fmt_reg.unwrap()));
return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val, std::move(fmt), {}, {}, std::move(reg)));
}
template<typename TC>
@@ -1132,7 +1140,7 @@ parse_offset_datetime(location& loc, const context<TC>& ctx)
std::get<0>(time_fmt_reg.unwrap())),
offset);
return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(val, std::move(fmt), {}, {}, std::move(reg)));
}
/* ============================================================================
@@ -1393,7 +1401,7 @@ parse_ml_basic_string(location& loc, const context<TC>& ctx)
}
return ok(basic_value<TC>(
std::move(val), std::move(fmt), {}, std::move(reg)
std::move(val), std::move(fmt), {}, {}, std::move(reg)
));
}
@@ -1473,7 +1481,7 @@ parse_basic_string(location& loc, const context<TC>& ctx)
auto val = std::move(val_res.unwrap().first );
auto reg = std::move(val_res.unwrap().second);
return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, std::move(reg)));
return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, {}, std::move(reg)));
}
template<typename TC>
@@ -1520,7 +1528,7 @@ parse_ml_literal_string(location& loc, const context<TC>& ctx)
string_type val(str.begin(), str.end());
return ok(basic_value<TC>(
std::move(val), std::move(fmt), {}, std::move(reg)
std::move(val), std::move(fmt), {}, {}, std::move(reg)
));
}
@@ -1573,7 +1581,7 @@ parse_literal_string(location& loc, const context<TC>& ctx)
auto reg = std::move(val_res.unwrap().second);
return ok(basic_value<TC>(
std::move(val), std::move(fmt), {}, std::move(reg)
std::move(val), std::move(fmt), {}, {}, std::move(reg)
));
}
@@ -1693,21 +1701,7 @@ parse_simple_key(location& loc, const context<TC>& ctx)
if(const auto bare = syntax::unquoted_key(spec).scan(loc))
{
const auto reg = bare.as_string();
// here we cannot use `if constexpr` because it is C++11.
if(std::is_same<key_type, std::string>::value)
{
return ok(reg);
}
else
{
key_type k;
for(const auto c : reg)
{
k += typename key_type::value_type(c);
}
return ok(k);
}
return ok(string_conv<key_type>(bare.as_string()));
}
else
{
@@ -1799,6 +1793,9 @@ parse_key_value_pair(location& loc, context<TC>& ctx)
// loc = first;
return err(v_res.unwrap_err());
}
// set key reg/fmt
return ok(std::make_pair(std::move(key_res.unwrap()), std::move(v_res.unwrap())));
}
@@ -1855,7 +1852,14 @@ skip_multiline_spacer(location& loc, context<TC>& ctx, const bool newline_found
{
spacer.newline_found = true;
auto comment = comm.as_string();
if( ! comment.empty() && comment.back() == '\n') {comment.pop_back();}
if( ! comment.empty() && comment.back() == '\n')
{
comment.pop_back();
if (!comment.empty() && comment.back() == '\r')
{
comment.pop_back();
}
}
spacer.comments.push_back(std::move(comment));
spacer.indent_type = indent_char::none;
@@ -2048,7 +2052,7 @@ parse_array(location& loc, context<TC>& ctx)
}
return ok(basic_value<TC>(
std::move(val), std::move(fmt), {}, region(first, loc)
std::move(val), std::move(fmt), {}, {}, region(first, loc)
));
}
@@ -2205,7 +2209,7 @@ insert_value(const inserting_value_kind kind,
fmt.fmt = table_format::implicit;
}
current_table.emplace(key, value_type(
table_type{}, fmt, std::vector<std::string>{}, key_reg));
table_type{}, fmt, std::vector<std::string>{}, {}, key_reg));
assert(current_table.at(key).is_table());
current_table_ptr = std::addressof(current_table.at(key).as_table());
@@ -2352,7 +2356,8 @@ insert_value(const inserting_value_kind kind,
current_table.emplace(key, value_type(
array_type{ std::move(val) }, std::move(fmt),
std::vector<std::string>{}, std::move(key_reg)
std::vector<std::string>{}, key_format_info{},
key_reg, key_reg
));
assert( ! current_table.at(key).as_array().empty());
@@ -2603,7 +2608,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
}
basic_value<TC> retval(
std::move(table), std::move(fmt), {}, region(first, loc));
std::move(table), std::move(fmt), {}, {}, region(first, loc));
return ok(std::move(retval));
}
@@ -3170,10 +3175,10 @@ parse_file(location& loc, context<TC>& ctx)
if(loc.eof())
{
return ok(value_type(table_type(), table_format_info{}, {}, region(loc)));
return ok(value_type(table_type(), table_format_info{}, {}, {}, region(loc)));
}
value_type root(table_type(), table_format_info{}, {}, region(loc));
value_type root(table_type(), table_format_info{}, {}, {}, region(loc));
root.as_table_fmt().fmt = table_format::multiline;
root.as_table_fmt().indent_type = indent_char::none;
@@ -3278,7 +3283,7 @@ parse_file(location& loc, context<TC>& ctx)
table_format_info fmt;
fmt.fmt = table_format::multiline;
fmt.indent_type = indent_char::none;
auto tab = value_type(table_type{}, std::move(fmt), std::move(com), reg);
auto tab = value_type(table_type{}, std::move(fmt), std::move(com), {}, reg);
auto inserted = insert_value(inserting_value_kind::array_table,
std::addressof(root.as_table()),
@@ -3365,7 +3370,7 @@ parse_file(location& loc, context<TC>& ctx)
table_format_info fmt;
fmt.fmt = table_format::multiline;
fmt.indent_type = indent_char::none;
auto tab = value_type(table_type{}, std::move(fmt), std::move(com), reg);
auto tab = value_type(table_type{}, std::move(fmt), std::move(com), {}, reg);
auto inserted = insert_value(inserting_value_kind::std_table,
std::addressof(root.as_table()),
@@ -3440,7 +3445,7 @@ parse_impl(std::vector<location::char_type> cs, std::string fname, const spec& s
{
auto src = std::make_shared<std::vector<location::char_type>>(std::move(cs));
location loc(std::move(src), std::move(fname));
return ok(value_type(table_type(), table_format_info{}, std::vector<std::string>{}, region(loc)));
return ok(value_type(table_type(), table_format_info{}, std::vector<std::string>{}, {}, region(loc)));
}
// to simplify parser, add newline at the end if there is no LF.
@@ -3525,7 +3530,7 @@ try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::d
// read whole file as a sequence of char
assert(fsize >= 0);
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize), '\0');
is.read(reinterpret_cast<char*>(letters.data()), fsize);
is.read(reinterpret_cast<char*>(letters.data()), static_cast<std::streamsize>(fsize));
return detail::parse_impl<TC>(std::move(letters), std::move(fname), std::move(s));
}

View File

@@ -244,13 +244,13 @@ struct result
{
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(other.as_ok());
auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_);
assert(tmp == std::addressof(this->succ_));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.as_err());
auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.fail_);
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}
@@ -259,13 +259,13 @@ struct result
{
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.as_ok()));
auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_));
assert(tmp == std::addressof(this->succ_));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err()));
auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.fail_));
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}
@@ -276,13 +276,13 @@ struct result
this->cleanup();
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(other.as_ok());
auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_);
assert(tmp == std::addressof(this->succ_));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.as_err());
auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.fail_);
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}
@@ -294,13 +294,13 @@ struct result
this->cleanup();
if(other.is_ok())
{
auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.as_ok()));
auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_));
assert(tmp == std::addressof(this->succ_));
(void)tmp;
}
else
{
auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err()));
auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.fail_));
assert(tmp == std::addressof(this->fail_));
(void)tmp;
}

View File

@@ -59,13 +59,15 @@ class serializer
using array_type = typename value_type::array_type ;
using table_type = typename value_type::table_type ;
using char_type = typename string_type::value_type;
public:
explicit serializer(const spec& sp)
: spec_(sp), force_inline_(false), current_indent_(0)
{}
std::string operator()(const std::vector<key_type>& ks, const value_type& v)
string_type operator()(const std::vector<key_type>& ks, const value_type& v)
{
for(const auto& k : ks)
{
@@ -74,13 +76,13 @@ class serializer
return (*this)(v);
}
std::string operator()(const key_type& k, const value_type& v)
string_type operator()(const key_type& k, const value_type& v)
{
this->keys_.push_back(k);
return (*this)(v);
}
std::string operator()(const value_type& v)
string_type operator()(const value_type& v)
{
switch(v.type())
{
@@ -98,14 +100,14 @@ class serializer
}
case value_t::table :
{
std::string retval;
string_type retval;
if(this->keys_.empty()) // it might be the root table. emit comments here.
{
retval += format_comments(v.comments(), v.as_table_fmt().indent_type);
}
if( ! retval.empty()) // we have comment.
{
retval += '\n';
retval += char_type('\n');
}
retval += (*this)(v.as_table(), v.as_table_fmt(), v.comments(), v.location());
@@ -115,7 +117,7 @@ class serializer
{
if(this->spec_.ext_null_value)
{
return "null";
return string_conv<string_type>("null");
}
break;
}
@@ -131,12 +133,19 @@ class serializer
private:
std::string operator()(const boolean_type& b, const boolean_format_info&, const source_location&) // {{{
string_type operator()(const boolean_type& b, const boolean_format_info&, const source_location&) // {{{
{
if(b) { return std::string("true"); } else { return std::string("false"); }
if(b)
{
return string_conv<string_type>("true");
}
else
{
return string_conv<string_type>("false");
}
} // }}}
std::string operator()(const integer_type i, const integer_format_info& fmt, const source_location& loc) // {{{
string_type operator()(const integer_type i, const integer_format_info& fmt, const source_location& loc) // {{{
{
std::ostringstream oss;
this->set_locale(oss);
@@ -180,7 +189,6 @@ class serializer
retval += '_';
retval += fmt.suffix;
}
return retval;
}
else
{
@@ -193,13 +201,27 @@ class serializer
{
case integer_format::hex:
{
oss << std::setw(static_cast<int>(fmt.width)) << std::setfill('0') << std::hex << i;
return std::string("0x") + insert_spacer(oss.str());
oss << std::noshowbase
<< std::setw(static_cast<int>(fmt.width))
<< std::setfill('0')
<< std::hex;
if(fmt.uppercase)
{
oss << std::uppercase;
}
else
{
oss << std::nouppercase;
}
oss << i;
retval = std::string("0x") + insert_spacer(oss.str());
break;
}
case integer_format::oct:
{
oss << std::setw(static_cast<int>(fmt.width)) << std::setfill('0') << std::oct << i;
return std::string("0o") + insert_spacer(oss.str());
retval = std::string("0o") + insert_spacer(oss.str());
break;
}
case integer_format::bin:
{
@@ -228,7 +250,8 @@ class serializer
{
oss << *iter;
}
return std::string("0b") + oss.str();
retval = std::string("0b") + oss.str();
break;
}
default:
{
@@ -238,9 +261,10 @@ class serializer
}
}
}
return string_conv<string_type>(retval);
} // }}}
std::string operator()(const floating_type f, const floating_format_info& fmt, const source_location&) // {{{
string_type operator()(const floating_type f, const floating_format_info& fmt, const source_location&) // {{{
{
using std::isnan;
using std::isinf;
@@ -261,7 +285,7 @@ class serializer
oss << '_';
oss << fmt.suffix;
}
return oss.str();
return string_conv<string_type>(oss.str());
}
if(isinf(f))
@@ -276,7 +300,7 @@ class serializer
oss << '_';
oss << fmt.suffix;
}
return oss.str();
return string_conv<string_type>(oss.str());
}
switch(fmt.fmt)
@@ -301,7 +325,7 @@ class serializer
s += '_';
s += fmt.suffix;
}
return s;
return string_conv<string_type>(s);
}
case floating_format::fixed:
{
@@ -314,7 +338,7 @@ class serializer
{
oss << '_' << fmt.suffix;
}
return oss.str();
return string_conv<string_type>(oss.str());
}
case floating_format::scientific:
{
@@ -327,7 +351,7 @@ class serializer
{
oss << '_' << fmt.suffix;
}
return oss.str();
return string_conv<string_type>(oss.str());
}
case floating_format::hex:
{
@@ -335,14 +359,14 @@ class serializer
{
oss << std::hexfloat << f;
// suffix is only for decimal numbers.
return oss.str();
return string_conv<string_type>(oss.str());
}
else // no hex allowed. output with max precision.
{
oss << std::setprecision(std::numeric_limits<floating_type>::max_digits10)
<< std::scientific << f;
// suffix is only for decimal numbers.
return oss.str();
return string_conv<string_type>(oss.str());
}
}
default:
@@ -351,58 +375,58 @@ class serializer
{
oss << '_' << fmt.suffix;
}
return oss.str();
return string_conv<string_type>(oss.str());
}
}
} // }}}
std::string operator()(string_type s, const string_format_info& fmt, const source_location& loc) // {{{
string_type operator()(string_type s, const string_format_info& fmt, const source_location& loc) // {{{
{
std::string retval;
string_type retval;
switch(fmt.fmt)
{
case string_format::basic:
{
retval += '"';
retval += char_type('"');
retval += this->escape_basic_string(s);
retval += '"';
retval += char_type('"');
return retval;
}
case string_format::literal:
{
if(std::find(s.begin(), s.end(), '\n') != s.end())
if(std::find(s.begin(), s.end(), char_type('\n')) != s.end())
{
throw serialization_error(format_error("toml::serializer: "
"(non-multiline) literal string cannot have a newline",
loc, "here"), loc);
}
retval += '\'';
retval += char_type('\'');
retval += s;
retval += '\'';
retval += char_type('\'');
return retval;
}
case string_format::multiline_basic:
{
retval += "\"\"\"";
retval += string_conv<string_type>("\"\"\"");
if(fmt.start_with_newline)
{
retval += '\n';
retval += char_type('\n');
}
retval += this->escape_ml_basic_string(s);
retval += "\"\"\"";
retval += string_conv<string_type>("\"\"\"");
return retval;
}
case string_format::multiline_literal:
{
retval += "'''";
retval += string_conv<string_type>("'''");
if(fmt.start_with_newline)
{
retval += '\n';
retval += char_type('\n');
}
retval += s;
retval += "'''";
retval += string_conv<string_type>("'''");
return retval;
}
default:
@@ -414,19 +438,19 @@ class serializer
}
} // }}}
std::string operator()(const local_date_type& d, const local_date_format_info&, const source_location&) // {{{
string_type operator()(const local_date_type& d, const local_date_format_info&, const source_location&) // {{{
{
std::ostringstream oss;
oss << d;
return oss.str();
return string_conv<string_type>(oss.str());
} // }}}
std::string operator()(const local_time_type& t, const local_time_format_info& fmt, const source_location&) // {{{
string_type operator()(const local_time_type& t, const local_time_format_info& fmt, const source_location&) // {{{
{
return this->format_local_time(t, fmt.has_seconds, fmt.subsecond_precision);
} // }}}
std::string operator()(const local_datetime_type& dt, const local_datetime_format_info& fmt, const source_location&) // {{{
string_type operator()(const local_datetime_type& dt, const local_datetime_format_info& fmt, const source_location&) // {{{
{
std::ostringstream oss;
oss << dt.date;
@@ -437,11 +461,11 @@ class serializer
case datetime_delimiter_kind::space: { oss << ' '; break; }
default: { oss << 'T'; break; }
}
oss << this->format_local_time(dt.time, fmt.has_seconds, fmt.subsecond_precision);
return oss.str();
return string_conv<string_type>(oss.str()) +
this->format_local_time(dt.time, fmt.has_seconds, fmt.subsecond_precision);
} // }}}
std::string operator()(const offset_datetime_type& odt, const offset_datetime_format_info& fmt, const source_location&) // {{{
string_type operator()(const offset_datetime_type& odt, const offset_datetime_format_info& fmt, const source_location&) // {{{
{
std::ostringstream oss;
oss << odt.date;
@@ -452,12 +476,12 @@ class serializer
case datetime_delimiter_kind::space: { oss << ' '; break; }
default: { oss << 'T'; break; }
}
oss << this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision);
oss << string_conv<std::string>(this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision));
oss << odt.offset;
return oss.str();
return string_conv<string_type>(oss.str());
} // }}}
std::string operator()(const array_type& a, const array_format_info& fmt, const comment_type& com, const source_location& loc) // {{{
string_type operator()(const array_type& a, const array_format_info& fmt, const comment_type& com, const source_location& loc) // {{{
{
array_format f = fmt.fmt;
if(fmt.fmt == array_format::default_format)
@@ -546,7 +570,7 @@ class serializer
throw serialization_error("array of table must have its key. "
"use format(key, v)", loc);
}
std::string retval;
string_type retval;
for(const auto& e : a)
{
assert(e.is_table());
@@ -556,9 +580,9 @@ class serializer
retval += this->format_indent(e.as_table_fmt().indent_type);
this->current_indent_ -= e.as_table_fmt().name_indent;
retval += "[[";
retval += string_conv<string_type>("[[");
retval += this->format_keys(this->keys_).value();
retval += "]]\n";
retval += string_conv<string_type>("]]\n");
retval += this->format_ml_table(e.as_table(), e.as_table_fmt());
}
@@ -567,20 +591,20 @@ class serializer
else if(f == array_format::oneline)
{
// ignore comments. we cannot emit comments
std::string retval;
retval += "[";
string_type retval;
retval += char_type('[');
for(const auto& e : a)
{
this->force_inline_ = true;
retval += (*this)(e);
retval += ", ";
retval += string_conv<string_type>(", ");
}
if( ! a.empty())
{
retval.pop_back(); // ` `
retval.pop_back(); // `,`
}
retval += "]";
retval += char_type(']');
this->force_inline_ = false;
return retval;
}
@@ -588,32 +612,32 @@ class serializer
{
assert(f == array_format::multiline);
std::string retval;
retval += "[\n";
string_type retval;
retval += string_conv<string_type>("[\n");
for(const auto& e : a)
{
this->current_indent_ += fmt.body_indent;
retval += format_comments(e.comments(), fmt.indent_type);
retval += format_indent(fmt.indent_type);
retval += this->format_comments(e.comments(), fmt.indent_type);
retval += this->format_indent(fmt.indent_type);
this->current_indent_ -= fmt.body_indent;
this->force_inline_ = true;
retval += (*this)(e);
retval += ",\n";
retval += string_conv<string_type>(",\n");
}
this->force_inline_ = false;
this->current_indent_ += fmt.closing_indent;
retval += format_indent(fmt.indent_type);
retval += this->format_indent(fmt.indent_type);
this->current_indent_ -= fmt.closing_indent;
retval += "]";
retval += char_type(']');
return retval;
}
} // }}}
std::string operator()(const table_type& t, const table_format_info& fmt, const comment_type& com, const source_location& loc) // {{{
string_type operator()(const table_type& t, const table_format_info& fmt, const comment_type& com, const source_location& loc) // {{{
{
if(this->force_inline_)
{
@@ -630,17 +654,17 @@ class serializer
{
if(fmt.fmt == table_format::multiline)
{
std::string retval;
string_type retval;
// comment is emitted inside format_ml_table
if(auto k = this->format_keys(this->keys_))
{
this->current_indent_ += fmt.name_indent;
retval += format_comments(com, fmt.indent_type);
retval += format_indent(fmt.indent_type);
retval += this->format_comments(com, fmt.indent_type);
retval += this->format_indent(fmt.indent_type);
this->current_indent_ -= fmt.name_indent;
retval += '[';
retval += char_type('[');
retval += k.value();
retval += "]\n";
retval += string_conv<string_type>("]\n");
}
// otherwise, its the root.
@@ -657,7 +681,7 @@ class serializer
}
else if(fmt.fmt == table_format::dotted)
{
std::vector<std::string> keys;
std::vector<string_type> keys;
if(this->keys_.empty())
{
throw serialization_error(format_error("toml::serializer: "
@@ -674,7 +698,7 @@ class serializer
{
assert(fmt.fmt == table_format::implicit);
std::string retval;
string_type retval;
for(const auto& kv : t)
{
const auto& k = kv.first;
@@ -722,46 +746,48 @@ class serializer
private:
std::string escape_basic_string(const std::string& s) const // {{{
string_type escape_basic_string(const string_type& s) const // {{{
{
std::string retval;
for(const char c : s)
string_type retval;
for(const char_type 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;}
case char_type('\\'): {retval += string_conv<string_type>("\\\\"); break;}
case char_type('\"'): {retval += string_conv<string_type>("\\\""); break;}
case char_type('\b'): {retval += string_conv<string_type>("\\b" ); break;}
case char_type('\t'): {retval += string_conv<string_type>("\\t" ); break;}
case char_type('\f'): {retval += string_conv<string_type>("\\f" ); break;}
case char_type('\n'): {retval += string_conv<string_type>("\\n" ); break;}
case char_type('\r'): {retval += string_conv<string_type>("\\r" ); break;}
default :
{
if(c == 0x1B && spec_.v1_1_0_add_escape_sequence_e)
if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e)
{
retval += "\\e";
retval += string_conv<string_type>("\\e");
}
else if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
else if((char_type(0x00) <= c && c <= char_type(0x08)) ||
(char_type(0x0A) <= c && c <= char_type(0x1F)) ||
c == char_type(0x7F))
{
if(spec_.v1_1_0_add_escape_sequence_x)
{
retval += "\\x";
retval += string_conv<string_type>("\\x");
}
else
{
retval += "\\u00";
retval += string_conv<string_type>("\\u00");
}
const auto c1 = c / 16;
const auto c2 = c % 16;
retval += static_cast<char>('0' + c1);
retval += static_cast<char_type>('0' + c1);
if(c2 < 10)
{
retval += static_cast<char>('0' + c2);
retval += static_cast<char_type>('0' + c2);
}
else // 10 <= c2
{
retval += static_cast<char>('A' + (c2 - 10));
retval += static_cast<char_type>('A' + (c2 - 10));
}
}
else
@@ -774,45 +800,47 @@ class serializer
return retval;
} // }}}
std::string escape_ml_basic_string(const std::string& s) // {{{
string_type escape_ml_basic_string(const string_type& s) // {{{
{
std::string retval;
for(const char c : s)
string_type retval;
for(const char_type c : s)
{
switch(c)
{
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;}
case char_type('\\'): {retval += string_conv<string_type>("\\\\"); break;}
case char_type('\b'): {retval += string_conv<string_type>("\\b" ); break;}
case char_type('\t'): {retval += string_conv<string_type>("\\t" ); break;}
case char_type('\f'): {retval += string_conv<string_type>("\\f" ); break;}
case char_type('\n'): {retval += string_conv<string_type>("\n" ); break;}
case char_type('\r'): {retval += string_conv<string_type>("\\r" ); break;}
default :
{
if(c == 0x1B && spec_.v1_1_0_add_escape_sequence_e)
if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e)
{
retval += "\\e";
retval += string_conv<string_type>("\\e");
}
else if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
else if((char_type(0x00) <= c && c <= char_type(0x08)) ||
(char_type(0x0A) <= c && c <= char_type(0x1F)) ||
c == char_type(0x7F))
{
if(spec_.v1_1_0_add_escape_sequence_x)
{
retval += "\\x";
retval += string_conv<string_type>("\\x");
}
else
{
retval += "\\u00";
retval += string_conv<string_type>("\\u00");
}
const auto c1 = c / 16;
const auto c2 = c % 16;
retval += static_cast<char>('0' + c1);
retval += static_cast<char_type>('0' + c1);
if(c2 < 10)
{
retval += static_cast<char>('0' + c2);
retval += static_cast<char_type>('0' + c2);
}
else // 10 <= c2
{
retval += static_cast<char>('A' + (c2 - 10));
retval += static_cast<char_type>('A' + (c2 - 10));
}
}
else
@@ -833,16 +861,16 @@ class serializer
// str5 = """Here are three quotation marks: ""\"."""
// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
// ```
auto found_3_quotes = retval.find("\"\"\"");
while(found_3_quotes != std::string::npos)
auto found_3_quotes = retval.find(string_conv<string_type>("\"\"\""));
while(found_3_quotes != string_type::npos)
{
retval.replace(found_3_quotes, 3, "\"\"\\\"");
found_3_quotes = retval.find("\"\"\"");
retval.replace(found_3_quotes, 3, string_conv<string_type>("\"\"\\\""));
found_3_quotes = retval.find(string_conv<string_type>("\"\"\""));
}
return retval;
} // }}}
std::string format_local_time(const local_time_type& t, const bool has_seconds, const std::size_t subsec_prec) // {{{
string_type format_local_time(const local_time_type& t, const bool has_seconds, const std::size_t subsec_prec) // {{{
{
std::ostringstream oss;
oss << std::setfill('0') << std::setw(2) << static_cast<int>(t.hour);
@@ -862,10 +890,10 @@ class serializer
oss << '.' << subsec_str.substr(0, subsec_prec);
}
}
return oss.str();
return string_conv<string_type>(oss.str());
} // }}}
std::string format_ml_table(const table_type& t, const table_format_info& fmt) // {{{
string_type format_ml_table(const table_type& t, const table_format_info& fmt) // {{{
{
const auto format_later = [](const value_type& v) -> bool {
@@ -881,7 +909,7 @@ class serializer
return is_ml_table || is_ml_array_table;
};
std::string retval;
string_type retval;
this->current_indent_ += fmt.body_indent;
for(const auto& kv : t)
{
@@ -902,9 +930,9 @@ class serializer
else
{
retval += format_key(key);
retval += " = ";
retval += string_conv<string_type>(" = ");
retval += (*this)(val);
retval += "\n";
retval += char_type('\n');
}
this->keys_.pop_back();
}
@@ -912,7 +940,7 @@ class serializer
if( ! retval.empty())
{
retval += "\n"; // for readability, add empty line between tables
retval += char_type('\n'); // for readability, add empty line between tables
}
for(const auto& kv : t)
{
@@ -929,33 +957,33 @@ class serializer
return retval;
} // }}}
std::string format_inline_table(const table_type& t, const table_format_info&) // {{{
string_type format_inline_table(const table_type& t, const table_format_info&) // {{{
{
// comments are ignored because we cannot write without newline
std::string retval;
retval += '{';
string_type retval;
retval += char_type('{');
for(const auto& kv : t)
{
this->force_inline_ = true;
retval += this->format_key(kv.first);
retval += " = ";
retval += string_conv<string_type>(" = ");
retval += (*this)(kv.second);
retval += ", ";
retval += string_conv<string_type>(", ");
}
if( ! t.empty())
{
retval.pop_back(); // ' '
retval.pop_back(); // ','
}
retval += '}';
retval += char_type('}');
this->force_inline_ = false;
return retval;
} // }}}
std::string format_ml_inline_table(const table_type& t, const table_format_info& fmt) // {{{
string_type format_ml_inline_table(const table_type& t, const table_format_info& fmt) // {{{
{
std::string retval;
retval += "{\n";
string_type retval;
retval += string_conv<string_type>("{\n");
this->current_indent_ += fmt.body_indent;
for(const auto& kv : t)
{
@@ -963,12 +991,12 @@ class serializer
retval += format_comments(kv.second.comments(), fmt.indent_type);
retval += format_indent(fmt.indent_type);
retval += kv.first;
retval += " = ";
retval += string_conv<string_type>(" = ");
this->force_inline_ = true;
retval += (*this)(kv.second);
retval += ",\n";
retval += string_conv<string_type>(",\n");
}
if( ! t.empty())
{
@@ -982,12 +1010,12 @@ class serializer
retval += format_indent(fmt.indent_type);
this->current_indent_ -= fmt.closing_indent;
retval += '}';
retval += char_type('}');
return retval;
} // }}}
std::string format_dotted_table(const table_type& t, const table_format_info& fmt, // {{{
const source_location&, std::vector<std::string>& keys)
string_type format_dotted_table(const table_type& t, const table_format_info& fmt, // {{{
const source_location&, std::vector<string_type>& keys)
{
// lets say we have: `{"a": {"b": {"c": {"d": "foo", "e": "bar"} } }`
// and `a` and `b` are `dotted`.
@@ -1003,7 +1031,7 @@ class serializer
// a.b.c.e = "bar"
// ```
std::string retval;
string_type retval;
for(const auto& kv : t)
{
@@ -1024,10 +1052,10 @@ class serializer
retval += format_comments(val.comments(), fmt.indent_type);
retval += format_indent(fmt.indent_type);
retval += format_keys(keys).value();
retval += " = ";
retval += string_conv<string_type>(" = ");
this->force_inline_ = true; // sub-table must be inlined
retval += (*this)(val);
retval += '\n';
retval += char_type('\n');
this->force_inline_ = false;
}
keys.pop_back();
@@ -1035,15 +1063,15 @@ class serializer
return retval;
} // }}}
std::string format_key(const key_type& key) // {{{
string_type format_key(const key_type& key) // {{{
{
if(key.empty())
{
return std::string("\"\"");
return string_conv<string_type>("\"\"");
}
// check the key can be a bare (unquoted) key
auto loc = detail::make_temporary_location(key);
auto loc = detail::make_temporary_location(string_conv<std::string>(key));
auto reg = detail::syntax::unquoted_key(this->spec_).scan(loc);
if(reg.is_ok() && loc.eof())
{
@@ -1051,41 +1079,43 @@ class serializer
}
//if it includes special characters, then format it in a "quoted" key.
std::string formatted("\"");
for(const char c : key)
string_type formatted = string_conv<string_type>("\"");
for(const char_type c : key)
{
switch(c)
{
case '\\': {formatted += "\\\\"; break;}
case '\"': {formatted += "\\\""; break;}
case '\b': {formatted += "\\b"; break;}
case '\t': {formatted += "\\t"; break;}
case '\f': {formatted += "\\f"; break;}
case '\n': {formatted += "\\n"; break;}
case '\r': {formatted += "\\r"; break;}
case char_type('\\'): {formatted += string_conv<string_type>("\\\\"); break;}
case char_type('\"'): {formatted += string_conv<string_type>("\\\""); break;}
case char_type('\b'): {formatted += string_conv<string_type>("\\b" ); break;}
case char_type('\t'): {formatted += string_conv<string_type>("\\t" ); break;}
case char_type('\f'): {formatted += string_conv<string_type>("\\f" ); break;}
case char_type('\n'): {formatted += string_conv<string_type>("\\n" ); break;}
case char_type('\r'): {formatted += string_conv<string_type>("\\r" ); break;}
default :
{
// ASCII ctrl char
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
if( (char_type(0x00) <= c && c <= char_type(0x08)) ||
(char_type(0x0A) <= c && c <= char_type(0x1F)) ||
c == char_type(0x7F))
{
if(spec_.v1_1_0_add_escape_sequence_x)
{
formatted += "\\x";
formatted += string_conv<string_type>("\\x");
}
else
{
formatted += "\\u00";
formatted += string_conv<string_type>("\\u00");
}
const auto c1 = c / 16;
const auto c2 = c % 16;
formatted += static_cast<char>('0' + c1);
formatted += static_cast<char_type>('0' + c1);
if(c2 < 10)
{
formatted += static_cast<char>('0' + c2);
formatted += static_cast<char_type>('0' + c2);
}
else // 10 <= c2
{
formatted += static_cast<char>('A' + (c2 - 10));
formatted += static_cast<char_type>('A' + (c2 - 10));
}
}
else
@@ -1096,58 +1126,58 @@ class serializer
}
}
}
formatted += "\"";
formatted += string_conv<string_type>("\"");
return formatted;
} // }}}
cxx::optional<std::string> format_keys(const std::vector<key_type>& keys) // {{{
cxx::optional<string_type> format_keys(const std::vector<key_type>& keys) // {{{
{
if(keys.empty())
{
return cxx::make_nullopt();
}
std::string formatted;
string_type formatted;
for(const auto& ky : keys)
{
formatted += format_key(ky);
formatted += '.';
formatted += char_type('.');
}
formatted.pop_back(); // remove the last dot '.'
return formatted;
} // }}}
std::string format_comments(const discard_comments&, const indent_char) const // {{{
string_type format_comments(const discard_comments&, const indent_char) const // {{{
{
return "";
return string_conv<string_type>("");
} // }}}
std::string format_comments(const preserve_comments& comments, const indent_char indent_type) const // {{{
string_type format_comments(const preserve_comments& comments, const indent_char indent_type) const // {{{
{
std::string retval;
string_type retval;
for(const auto& c : comments)
{
if(c.empty()) {continue;}
retval += format_indent(indent_type);
if(c.front() != '#') {retval += '#';}
retval += c;
if(c.back() != '\n') {retval += '\n';}
if(c.front() != '#') {retval += char_type('#');}
retval += string_conv<string_type>(c);
if(c.back() != '\n') {retval += char_type('\n');}
}
return retval;
} // }}}
std::string format_indent(const indent_char indent_type) const // {{{
string_type format_indent(const indent_char indent_type) const // {{{
{
const auto indent = static_cast<std::size_t>((std::max)(0, this->current_indent_));
if(indent_type == indent_char::space)
{
return detail::make_string(indent, ' ');
return string_conv<string_type>(make_string(indent, ' '));
}
else if(indent_type == indent_char::tab)
{
return detail::make_string(indent, '\t');
return string_conv<string_type>(make_string(indent, '\t'));
}
else
{
return "";
return string_type{};
}
} // }}}
@@ -1166,29 +1196,38 @@ class serializer
} // detail
template<typename TC>
std::string format(const basic_value<TC>& v,
const spec s = spec::default_version())
typename basic_value<TC>::string_type
format(const basic_value<TC>& v, const spec s = spec::default_version())
{
detail::serializer<TC> ser(s);
return ser(v);
}
template<typename TC>
std::string format(const typename basic_value<TC>::key_type& k,
const basic_value<TC>& v,
const spec s = spec::default_version())
typename basic_value<TC>::string_type
format(const typename basic_value<TC>::key_type& k,
const basic_value<TC>& v,
const spec s = spec::default_version())
{
detail::serializer<TC> ser(s);
return ser(k, v);
}
template<typename TC>
std::string format(const std::vector<typename basic_value<TC>::key_type>& ks,
const basic_value<TC>& v,
const spec s = spec::default_version())
typename basic_value<TC>::string_type
format(const std::vector<typename basic_value<TC>::key_type>& ks,
const basic_value<TC>& v,
const spec s = spec::default_version())
{
detail::serializer<TC> ser(s);
return ser(ks, v);
}
template<typename TC>
std::ostream& operator<<(std::ostream& os, const basic_value<TC>& v)
{
os << format(v);
return os;
}
} // toml
#if defined(TOML11_COMPILE_SOURCES)
@@ -1197,25 +1236,25 @@ namespace toml
struct type_config;
struct ordered_type_config;
extern template std::string
extern template typename basic_value<type_config>::string_type
format<type_config>(const basic_value<type_config>&, const spec);
extern template std::string
extern template typename basic_value<type_config>::string_type
format<type_config>(const typename basic_value<type_config>::key_type& k,
const basic_value<type_config>& v, const spec);
extern template std::string
extern template typename basic_value<type_config>::string_type
format<type_config>(const std::vector<typename basic_value<type_config>::key_type>& ks,
const basic_value<type_config>& v, const spec s);
extern template std::string
extern template typename basic_value<type_config>::string_type
format<ordered_type_config>(const basic_value<ordered_type_config>&, const spec);
extern template std::string
extern template typename basic_value<type_config>::string_type
format<ordered_type_config>(const typename basic_value<ordered_type_config>::key_type& k,
const basic_value<ordered_type_config>& v, const spec);
extern template std::string
extern template typename basic_value<type_config>::string_type
format<ordered_type_config>(const std::vector<typename basic_value<ordered_type_config>::key_type>& ks,
const basic_value<ordered_type_config>& v, const spec s);

View File

@@ -83,6 +83,14 @@ struct has_into_toml_method_impl
static std::false_type check(...);
};
struct has_template_into_toml_method_impl
{
template<typename T, typename TypeConfig>
static std::true_type check(decltype(std::declval<T>().template into_toml<TypeConfig>())*);
template<typename T, typename TypeConfig>
static std::false_type check(...);
};
struct has_specialized_from_impl
{
template<typename T>
@@ -126,6 +134,9 @@ struct has_from_toml_method: decltype(has_from_toml_method_impl::check<T, TC>(nu
template<typename T>
struct has_into_toml_method: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
template<typename T, typename TypeConfig>
struct has_template_into_toml_method: decltype(has_template_into_toml_method_impl::check<T, TypeConfig>(nullptr)){};
template<typename T>
struct has_specialized_from: decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
@@ -162,6 +173,32 @@ struct is_std_forward_list_impl<std::forward_list<T>> : std::true_type{};
template<typename T>
using is_std_forward_list = is_std_forward_list_impl<cxx::remove_cvref_t<T>>;
template<typename T> struct is_std_basic_string_impl : std::false_type{};
template<typename C, typename T, typename A>
struct is_std_basic_string_impl<std::basic_string<C, T, A>> : std::true_type{};
template<typename T>
using is_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;
template<typename T> struct is_1byte_std_basic_string_impl : std::false_type{};
template<typename C, typename T, typename A>
struct is_1byte_std_basic_string_impl<std::basic_string<C, T, A>>
: std::integral_constant<bool, sizeof(C) == sizeof(char)> {};
template<typename T>
using is_1byte_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;
#if defined(TOML11_HAS_STRING_VIEW)
template<typename T> struct is_std_basic_string_view_impl : std::false_type{};
template<typename C, typename T>
struct is_std_basic_string_view_impl<std::basic_string_view<C, T>> : std::true_type{};
template<typename T>
using is_std_basic_string_view = is_std_basic_string_view_impl<cxx::remove_cvref_t<T>>;
template<typename V, typename S>
struct is_string_view_of : std::false_type {};
template<typename C, typename T>
struct is_string_view_of<std::basic_string_view<C, T>, std::basic_string<C, T>> : std::true_type {};
#endif
template<typename T> struct is_chrono_duration_impl: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration_impl<std::chrono::duration<Rep, Period>>: std::true_type{};

View File

@@ -99,6 +99,72 @@ inline std::string make_string(std::size_t len, char c)
return std::string(len, c);
}
// ---------------------------------------------------------------------------
template<typename Char, typename Traits, typename Alloc,
typename Char2, typename Traits2, typename Alloc2>
struct string_conv_impl
{
static_assert(sizeof(Char) == sizeof(char), "");
static_assert(sizeof(Char2) == sizeof(char), "");
static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char2, Traits2, Alloc2> s)
{
std::basic_string<Char, Traits, Alloc> retval;
std::transform(s.begin(), s.end(), std::back_inserter(retval),
[](const Char2 c) {return static_cast<Char>(c);});
return retval;
}
template<std::size_t N>
static std::basic_string<Char, Traits, Alloc> invoke(const Char2 (&s)[N])
{
std::basic_string<Char, Traits, Alloc> retval;
// "string literal" has null-char at the end. to skip it, we use prev.
std::transform(std::begin(s), std::prev(std::end(s)), std::back_inserter(retval),
[](const Char2 c) {return static_cast<Char>(c);});
return retval;
}
};
template<typename Char, typename Traits, typename Alloc>
struct string_conv_impl<Char, Traits, Alloc, Char, Traits, Alloc>
{
static_assert(sizeof(Char) == sizeof(char), "");
static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char, Traits, Alloc> s)
{
return s;
}
template<std::size_t N>
static std::basic_string<Char, Traits, Alloc> invoke(const Char (&s)[N])
{
return std::basic_string<Char, Traits, Alloc>(s);
}
};
template<typename S, typename Char2, typename Traits2, typename Alloc2>
cxx::enable_if_t<is_std_basic_string<S>::value, S>
string_conv(std::basic_string<Char2, Traits2, Alloc2> s)
{
using C = typename S::value_type;
using T = typename S::traits_type;
using A = typename S::allocator_type;
return string_conv_impl<C, T, A, Char2, Traits2, Alloc2>::invoke(std::move(s));
}
template<typename S, std::size_t N>
cxx::enable_if_t<is_std_basic_string<S>::value, S>
string_conv(const char (&s)[N])
{
using C = typename S::value_type;
using T = typename S::traits_type;
using A = typename S::allocator_type;
using C2 = char;
using T2 = std::char_traits<C2>;
using A2 = std::allocator<C2>;
return string_conv_impl<C, T, A, C2, T2, A2>::template invoke<N>(s);
}
} // namespace detail
} // namespace toml
#endif // TOML11_UTILITY_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@
#define TOML11_VERSION_HPP
#define TOML11_VERSION_MAJOR 4
#define TOML11_VERSION_MINOR 0
#define TOML11_VERSION_PATCH 2
#define TOML11_VERSION_MINOR 1
#define TOML11_VERSION_PATCH 0
#ifndef __cplusplus
# error "__cplusplus is not defined"
@@ -57,6 +57,11 @@
#define TOML11_CXX20_VALUE 202002L
#endif//TOML11_CXX20_VALUE
#if defined(__cpp_char8_t)
# if __cpp_char8_t >= 201811L
# define TOML11_HAS_CHAR8_T 1
# endif
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE
# if __has_include(<string_view>)

View File

@@ -40,6 +40,7 @@ enum class string_format : std::uint8_t;
enum class datetime_delimiter_kind : std::uint8_t;
enum class array_format : std::uint8_t;
enum class table_format : std::uint8_t;
enum class key_format : std::uint8_t;
struct boolean_format_info;
struct integer_format_info;
@@ -51,6 +52,7 @@ struct local_date_format_info;
struct local_time_format_info;
struct array_format_info;
struct table_format_info;
struct key_format_info;
template<typename Key, typename Val, typename Cmp, typename Allocator>
class ordered_map;

File diff suppressed because it is too large Load Diff

View File

@@ -99,6 +99,7 @@ if(TOML11_PRECOMPILE)
# required options to use toml11 with MSVC
if(MSVC)
target_compile_options(toml11 PUBLIC "/utf-8")
target_compile_options(toml11 PRIVATE "/W4" "/WX")
if(MSVC_VERSION LESS 1910)
message(STATUS "MSVC < 1910. DEFINE_CONVERSION_NON_INTRUSIVE is disabled")
target_compile_definitions(toml11 PUBLIC -DTOML11_WITHOUT_DEFINE_NON_INTRUSIVE)
@@ -107,6 +108,22 @@ if(TOML11_PRECOMPILE)
else() # MSVC 2019
target_compile_options(toml11 PUBLIC "/Zc:preprocessor")
endif()
else()
target_compile_options(toml11 PRIVATE
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WERROR}>: -Werror >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
)
endif()
else()
add_library(toml11 INTERFACE)

View File

@@ -10,25 +10,25 @@ namespace toml
struct type_config;
struct ordered_type_config;
template std::string
template typename basic_value<type_config>::string_type
format<type_config>(const basic_value<type_config>&, const spec);
template std::string
template typename basic_value<type_config>::string_type
format<type_config>(const typename basic_value<type_config>::key_type& k,
const basic_value<type_config>& v, const spec);
template std::string
template typename basic_value<type_config>::string_type
format<type_config>(const std::vector<typename basic_value<type_config>::key_type>& ks,
const basic_value<type_config>& v, const spec s);
template std::string
template typename basic_value<type_config>::string_type
format<ordered_type_config>(const basic_value<ordered_type_config>&, const spec);
template std::string
template typename basic_value<type_config>::string_type
format<ordered_type_config>(const typename basic_value<ordered_type_config>::key_type& k,
const basic_value<ordered_type_config>& v, const spec);
template std::string
template typename basic_value<type_config>::string_type
format<ordered_type_config>(const std::vector<typename basic_value<ordered_type_config>::key_type>& ks,
const basic_value<ordered_type_config>& v, const spec s);

View File

@@ -41,23 +41,6 @@ set(TOML11_TEST_NAMES
test_visit
)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-Wall" COMPILER_SUPPORTS_WALL)
check_cxx_compiler_flag("-Wextra" COMPILER_SUPPORTS_WEXTRA)
check_cxx_compiler_flag("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
check_cxx_compiler_flag("-Werror" COMPILER_SUPPORTS_WERROR)
check_cxx_compiler_flag("-Wsign-conversion" COMPILER_SUPPORTS_WSIGN_CONVERSION)
check_cxx_compiler_flag("-Wconversion" COMPILER_SUPPORTS_WCONVERSION)
check_cxx_compiler_flag("-Wduplicated-cond" COMPILER_SUPPORTS_WDUPLICATED_COND)
check_cxx_compiler_flag("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
check_cxx_compiler_flag("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
check_cxx_compiler_flag("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
check_cxx_compiler_flag("-Wrange-loop-analysis" COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
check_cxx_compiler_flag("-Wundef" COMPILER_SUPPORTS_WUNDEF)
check_cxx_compiler_flag("-Wshadow" COMPILER_SUPPORTS_WSHADOW)
if(BUILD_TESTING)
add_library(toml11_test_utility STATIC utility.cpp)
target_include_directories(toml11_test_utility
@@ -72,27 +55,28 @@ if(BUILD_TESTING)
)
target_link_libraries(${TEST_NAME} PUBLIC toml11 toml11_test_utility)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W3)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
else()
target_compile_options(${TEST_NAME} PRIVATE
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WERROR}>: -Werror >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
target_link_options(${TEST_NAME} PRIVATE
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
@@ -111,27 +95,27 @@ if(TOML11_BUILD_TOML_TESTS)
)
target_link_libraries(toml11_decoder PRIVATE toml11)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W3)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
else()
target_compile_options(toml11_decoder PRIVATE
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
target_link_options(toml11_decoder PRIVATE
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
endif()
@@ -143,7 +127,7 @@ if(TOML11_BUILD_TOML_TESTS)
target_compile_definitions(toml11_decoder_v1_1_0 PRIVATE -DTOML11_TO_JSON_USE_V1_1_0)
target_link_libraries(toml11_decoder_v1_1_0 PRIVATE toml11)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W3)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
else()
target_compile_options(toml11_decoder_v1_1_0 PRIVATE
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
@@ -174,27 +158,27 @@ if(TOML11_BUILD_TOML_TESTS)
)
target_link_libraries(toml11_encoder PRIVATE toml11)
if(MSVC)
target_compile_options(${TEST_NAME} PRIVATE /W3)
target_compile_options(${TEST_NAME} PRIVATE /W4 /WX)
else()
target_compile_options(toml11_encoder PRIVATE
$<$<BOOL:${COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WALL}>: -Wall >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WEXTRA}>: -Wextra >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WPEDANTIC}>: -Wpedantic >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSIGN_CONVERSION}>: -Wsign-conversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WCONVERSION}>: -Wconversion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_COND}>: -Wduplicated-cond >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDUPLICATED_BRANCHES}>: -Wduplicated-branches>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WLOGICAL_OP}>: -Wlogical-op >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WDOUBLE_PROMOTION}>: -Wdouble-promotion >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS}>: -Wrange-loop-analysis>
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WUNDEF}>: -Wundef >
$<$<BOOL:${TOML11_COMPILER_SUPPORTS_WSHADOW}>: -Wshadow >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
target_link_options(toml11_encoder PRIVATE
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
$<$<BOOL:${TOML11_TEST_WITH_ASAN}>: -fsanitize=address >
$<$<BOOL:${TOML11_TEST_WITH_UBSAN}>: -fsanitize=undefined >
)
endif()
endif(TOML11_BUILD_TOML_TESTS)

View File

@@ -627,14 +627,29 @@ TEST_CASE("testing toml::find string conversion")
toml::find<std::string>(v, "key") += "bar";
CHECK_EQ("foobar", toml::find<std::string>(v, "key"));
}
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if defined(TOML11_HAS_CHAR8_T)
TEST_CASE("testing toml::find<string-like>")
{
using value_type = toml::value;
{
value_type v = toml::table{{"key", "foo"}};
CHECK_EQ("foo", toml::find<std::string_view>(v, "key"));
CHECK_EQ(u8"foo", toml::find<std::u8string>(v, "key"));
}
#endif
}
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
TEST_CASE("testing toml::get<string_view>")
{
using value_type = toml::value;
{
value_type v("foo");
CHECK_EQ("foo", toml::get<std::string_view>(v));
}
}
#endif
TEST_CASE("testing toml::find array conversion")
{

View File

@@ -4,6 +4,7 @@
#include <toml11/parser.hpp>
#include <toml11/serializer.hpp>
#include <toml11/types.hpp>
#include <toml11/literal.hpp>
TEST_CASE("testing decimal")
{
@@ -25,19 +26,40 @@ TEST_CASE("testing decimal")
TEST_CASE("testing hex")
{
const auto hex_fmt = [](std::size_t w, std::size_t s) {
const auto hex_fmt = [](bool u, std::size_t w, std::size_t s) {
toml::integer_format_info fmt;
fmt.fmt = toml::integer_format::hex;
fmt.uppercase = u;
fmt.width = w;
fmt.spacer = s;
return fmt;
};
CHECK_EQ("0xdeadbeef", toml::format(toml::value(0xDEADBEEF, hex_fmt(8, 0))));
CHECK_EQ("0xdead_beef", toml::format(toml::value(0xDEADBEEF, hex_fmt(8, 4))));
CHECK_EQ("0xff", toml::format(toml::value(0xFF, hex_fmt(2, 0))));
CHECK_EQ("0x00ff", toml::format(toml::value(0xFF, hex_fmt(4, 0))));
CHECK_EQ("0x0000ff", toml::format(toml::value(0xFF, hex_fmt(6, 0))));
CHECK_EQ("0xdeadbeef", toml::format(toml::value(0xDEADBEEF, hex_fmt(false, 8, 0))));
CHECK_EQ("0xdead_beef", toml::format(toml::value(0xDEADBEEF, hex_fmt(false, 8, 4))));
CHECK_EQ("0xff", toml::format(toml::value(0xFF, hex_fmt(false, 2, 0))));
CHECK_EQ("0x00ff", toml::format(toml::value(0xFF, hex_fmt(false, 4, 0))));
CHECK_EQ("0x0000ff", toml::format(toml::value(0xFF, hex_fmt(false, 6, 0))));
CHECK_EQ("0xDEADBEEF", toml::format(toml::value(0xDEADBEEF, hex_fmt(true, 8, 0))));
CHECK_EQ("0xDEAD_BEEF", toml::format(toml::value(0xDEADBEEF, hex_fmt(true, 8, 4))));
CHECK_EQ("0xFF", toml::format(toml::value(0xFF, hex_fmt(true, 2, 0))));
CHECK_EQ("0x00FF", toml::format(toml::value(0xFF, hex_fmt(true, 4, 0))));
CHECK_EQ("0x0000FF", toml::format(toml::value(0xFF, hex_fmt(true, 6, 0))));
using namespace toml::literals::toml_literals;
CHECK_EQ("0xdeadbeef", toml::format("0xdeadbeef"_toml ));
CHECK_EQ("0xdead_beef", toml::format("0xdead_beef"_toml));
CHECK_EQ("0xff", toml::format("0xff"_toml ));
CHECK_EQ("0x00ff", toml::format("0x00ff"_toml ));
CHECK_EQ("0x0000ff", toml::format("0x0000ff"_toml ));
CHECK_EQ("0xDEADBEEF", toml::format("0xDEADBEEF"_toml ));
CHECK_EQ("0xDEAD_BEEF", toml::format("0xDEAD_BEEF"_toml));
CHECK_EQ("0xFF", toml::format("0xFF"_toml ));
CHECK_EQ("0x00FF", toml::format("0x00FF"_toml ));
CHECK_EQ("0x0000FF", toml::format("0x0000FF"_toml ));
}
TEST_CASE("testing oct")

View File

@@ -240,8 +240,19 @@ TEST_CASE("testing toml::get<floating-like>")
}
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if defined(TOML11_HAS_CHAR8_T)
TEST_CASE("testing toml::get<string-like>")
{
using value_type = toml::value;
{
value_type v("foo");
CHECK_EQ(u8"foo", toml::get<std::u8string>(v));
}
}
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
TEST_CASE("testing toml::get<string_view>")
{
using value_type = toml::value;
{

View File

@@ -34,23 +34,29 @@ TEST_CASE("testing decimal_value")
TEST_CASE("testing hex_value")
{
toml::detail::context<toml::type_config> ctx(toml::spec::v(1,0,0));
const auto hex_fmt = [](std::size_t w, std::size_t s) {
const auto hex_fmt = [](bool u, std::size_t w, std::size_t s) {
toml::integer_format_info fmt;
fmt.fmt = toml::integer_format::hex;
fmt.uppercase = u;
fmt.width = w;
fmt.spacer = s;
return fmt;
};
toml11_test_parse_success<toml::value_t::integer>("0xDEADBEEF", 0xDEADBEEF, comments(), hex_fmt(8, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xdeadbeef", 0xDEADBEEF, comments(), hex_fmt(8, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xDEADbeef", 0xDEADBEEF, comments(), hex_fmt(8, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xDEAD_BEEF", 0xDEADBEEF, comments(), hex_fmt(8, 4), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xdead_beef", 0xDEADBEEF, comments(), hex_fmt(8, 4), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xdead_BEEF", 0xDEADBEEF, comments(), hex_fmt(8, 4), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xFF", 0xFF, comments(), hex_fmt(2, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x00FF", 0xFF, comments(), hex_fmt(4, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x0000FF", 0xFF, comments(), hex_fmt(6, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xDEADBEEF", 0xDEADBEEF, comments(), hex_fmt(true, 8, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xdeadbeef", 0xDEADBEEF, comments(), hex_fmt(false, 8, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xDEADbeef", 0xDEADBEEF, comments(), hex_fmt(true, 8, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xDEAD_BEEF", 0xDEADBEEF, comments(), hex_fmt(true, 8, 4), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xdead_beef", 0xDEADBEEF, comments(), hex_fmt(false, 8, 4), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xdead_BEEF", 0xDEADBEEF, comments(), hex_fmt(true, 8, 4), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xFF", 0xFF, comments(), hex_fmt(true, 2, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x00FF", 0xFF, comments(), hex_fmt(true, 4, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x0000FF", 0xFF, comments(), hex_fmt(true, 6, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0xff", 0xFF, comments(), hex_fmt(false, 2, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x00ff", 0xFF, comments(), hex_fmt(false, 4, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x0000ff", 0xFF, comments(), hex_fmt(false, 6, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x00", 0, comments(), hex_fmt(true, 2, 0), ctx);
toml11_test_parse_success<toml::value_t::integer>("0x12345", 0x12345, comments(), hex_fmt(true, 5, 0), ctx);
}
TEST_CASE("testing oct_value")

View File

@@ -49,6 +49,25 @@ struct foobar
int a;
std::string b;
};
struct corge
{
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 ;
}
template <typename TC>
toml::basic_value<TC> into_toml() const
{
return toml::basic_value<TC>(typename toml::basic_value<TC>::table_type{{"a", this->a}, {"b", this->b}});
}
};
} // extlib
namespace toml
@@ -215,6 +234,19 @@ TEST_CASE("test_conversion_by_member_methods")
CHECK(v == v2);
}
{
const toml::value v(toml::table{{"a", 42}, {"b", "baz"}});
const auto corge = toml::get<extlib::corge>(v);
CHECK_EQ(corge.a, 42);
CHECK_EQ(corge.b, "baz");
const toml::value v2(corge);
CHECK_EQ(v, v2);
}
{
const toml::ordered_value v(toml::ordered_table{{"a", 42}, {"b", "baz"}});

View File

@@ -587,6 +587,105 @@ TEST_CASE("testing constructor (string_view)")
}
#endif
#ifdef TOML11_HAS_CHAR8_T
TEST_CASE("testing constructor (u8string)")
{
toml::string_format_info fmt;
fmt.fmt = toml::string_format::basic;
const std::string eq("hoge");
const std::string ne("fuga");
const std::u8string ref(u8"hoge");
{
toml::value x(ref);
test_is_type(x, toml::value_t::string);
test_as_type_throws(x, toml::value_t::string);
test_as_type_fmt_throws(x, toml::value_t::string);
test_as_type<toml::value_t::string>(x, "hoge", "fuga");
}
// -----------------------------------------------------------------------
{
toml::value x_with_comments(ref, std::vector<std::string>{"foo", "bar"});
test_is_type (x_with_comments, toml::value_t::string);
test_as_type_throws (x_with_comments, toml::value_t::string);
test_as_type_fmt_throws(x_with_comments, toml::value_t::string);
test_as_type<toml::value_t::string>(x_with_comments, eq, ne);
CHECK_EQ(x_with_comments.comments().size(), 2);
CHECK_EQ(x_with_comments.comments().at(0), "foo");
CHECK_EQ(x_with_comments.comments().at(1), "bar");
CHECK_EQ(x_with_comments.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_with_format(eq, fmt);
test_is_type (x_with_format, toml::value_t::string);
test_as_type_throws (x_with_format, toml::value_t::string);
test_as_type_fmt_throws(x_with_format, toml::value_t::string);
test_as_type <toml::value_t::string>(x_with_format, eq, ne);
test_as_type_fmt<toml::value_t::string>(x_with_format, fmt);
CHECK_EQ(x_with_format.comments().size(), 0);
CHECK_EQ(x_with_format.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_with_com_fmt(ref, fmt,
std::vector<std::string>{"foo", "bar"});
test_is_type (x_with_com_fmt, toml::value_t::string);
test_as_type_throws (x_with_com_fmt, toml::value_t::string);
test_as_type_fmt_throws(x_with_com_fmt, toml::value_t::string);
test_as_type <toml::value_t::string>(x_with_com_fmt, eq, ne);
test_as_type_fmt<toml::value_t::string>(x_with_com_fmt, fmt);
CHECK_EQ(x_with_com_fmt.comments().size(), 2);
CHECK_EQ(x_with_com_fmt.comments().at(0), "foo");
CHECK_EQ(x_with_com_fmt.comments().at(1), "bar");
CHECK_EQ(x_with_com_fmt.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_assign(ne, fmt);
x_assign = ref;
test_is_type (x_assign, toml::value_t::string);
test_as_type_throws (x_assign, toml::value_t::string);
test_as_type_fmt_throws(x_assign, toml::value_t::string);
test_as_type <toml::value_t::string>(x_assign, eq, ne);
test_as_type_fmt<toml::value_t::string>(x_assign, fmt);
CHECK_EQ(x_assign.comments().size(), 0);
CHECK_EQ(x_assign.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_assign_different_type(true);
x_assign_different_type = ref;
test_is_type (x_assign_different_type, toml::value_t::string);
test_as_type_throws (x_assign_different_type, toml::value_t::string);
test_as_type_fmt_throws(x_assign_different_type, toml::value_t::string);
test_as_type<toml::value_t::string>(x_assign_different_type, eq, ne);
CHECK_EQ(x_assign_different_type.comments().size(), 0);
CHECK_EQ(x_assign_different_type.location().is_ok(), false);
}
}
#endif
TEST_CASE("testing constructor (local_date)")
{
toml::local_date_format_info fmt;

View File

@@ -29,10 +29,11 @@ namespace toml
std::ostream& operator<<(std::ostream& os, const integer_format_info& fmt)
{
os << "integer_format_info{";
os << "fmt = " << fmt.fmt << ", ";
os << "width = " << fmt.width << ", ";
os << "spacer = " << fmt.spacer << ", ";
os << "suffix = \"" << fmt.suffix << "\"}";
os << "fmt = " << fmt.fmt << ", ";
os << "uppercase = " << fmt.uppercase << ", ";
os << "width = " << fmt.width << ", ";
os << "spacer = " << fmt.spacer << ", ";
os << "suffix = \"" << fmt.suffix << "\"}";
return os;
}
std::ostream& operator<<(std::ostream& os, const floating_format_info& fmt)

View File

@@ -86,13 +86,6 @@ void toml11_test_parse_failure(F fn, std::string in, toml::detail::context<TC> c
namespace toml
{
template<typename TC>
std::ostream& operator<<(std::ostream& os, const toml::basic_value<TC>& v)
{
os << toml::format(v);
return os;
}
std::ostream& operator<<(std::ostream& os, const integer_format_info&);
std::ostream& operator<<(std::ostream& os, const floating_format_info&);
std::ostream& operator<<(std::ostream& os, const string_format_info&);