Compare commits

..

9 Commits

Author SHA1 Message Date
ToruNiina
3bf4ac0965 doc: update Fuzzy search section 2019-09-01 14:50:01 +09:00
ToruNiina
d53026837a test: add test for find<T> and check throw 2019-09-01 14:46:46 +09:00
ToruNiina
6d31cccc5b feat: throw if multiple keys match to the key 2019-09-01 14:45:56 +09:00
ToruNiina
99e46813f4 doc: add Fuzzy search section to README 2019-08-31 20:11:31 +09:00
ToruNiina
c0df39ca49 test: add test for find_fuzzy 2019-08-31 19:30:19 +09:00
ToruNiina
3e6747cfeb feat: add find_fuzzy and suggeston
Add the following
- find_fuzzy<T>(val, "key")
- find<T>(val, "key", FuzzyMatcher) to suggest typo
- levenstein_matcher
2019-08-31 19:28:50 +09:00
ToruNiina
4cebd660fd refactor: use as_xxx to cast toml value
and store rvalue reference as a value instead of lvalue
2019-08-31 18:22:36 +09:00
ToruNiina
43907de365 refactor: check key types in find(v, k1, k2, ...)
ks should be convertible to toml::key
2019-08-31 17:28:07 +09:00
ToruNiina
9b43171b65 refactor: split get.hpp to get/find.hpp 2019-08-31 14:49:00 +09:00
82 changed files with 3781 additions and 8369 deletions

View File

@@ -2,8 +2,10 @@ version: 2.1
jobs:
test_suite:
environment:
- GOPATH: /home/circleci/go
docker:
- image: cimg/go:1.16
- image: circleci/golang:1.9
steps:
- checkout
- run:
@@ -11,15 +13,8 @@ jobs:
g++ --version
cd tests/
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test
export PATH=$(pwd):${PATH}
git clone --depth 1 --branch v1.3.0 https://github.com/BurntSushi/toml-test.git
cd toml-test/
go install -v ./cmd/toml-test
cd -
toml-test check_toml_test
# go clean -modcache
# go get github.com/BurntSushi/toml-test/cmd/toml-test
# $GOPATH/bin/toml-test ./check_toml_test
go get github.com/BurntSushi/toml-test
$GOPATH/bin/toml-test ./check_toml_test
test_serialization:
docker:
- image: circleci/buildpack-deps:bionic

View File

@@ -1,6 +0,0 @@
FROM gcr.io/oss-fuzz-base/base-builder
RUN apt-get update && apt-get install -y make autoconf automake libtool
COPY . $SRC/toml11
COPY .clusterfuzzlite/build.sh $SRC/build.sh
WORKDIR $SRC/toml11

View File

@@ -1,3 +0,0 @@
# ClusterFuzzLite set up
This folder contains a fuzzing set for [ClusterFuzzLite](https://google.github.io/clusterfuzzlite).

View File

@@ -1,6 +0,0 @@
#!/bin/bash -eu
# Copy fuzzer executable to $OUT/
$CXX $CFLAGS $LIB_FUZZING_ENGINE \
$SRC/toml11/.clusterfuzzlite/parse_fuzzer.cpp \
-o $OUT/parse_fuzzer \
-I$SRC/toml11/

View File

@@ -1,16 +0,0 @@
#include <toml.hpp>
#include <sstream>
#include <string>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
std::string s(reinterpret_cast<const char *>(data), size);
std::istringstream iss(s);
try {
const auto ref = toml::parse(iss);
} catch (...) {
}
return 0;
}

View File

@@ -1 +0,0 @@
language: c++

View File

@@ -1,13 +0,0 @@
root = true
[*]
indent_style = space
[CMakeLists.txt]
indent_size = 4
[*.{c,h}*]
indent_size = 4
[*.{md,yml}]
indent_size = 2

View File

@@ -1,30 +0,0 @@
name: ClusterFuzzLite PR fuzzing
on:
workflow_dispatch:
pull_request:
branches: [ master ]
permissions: read-all
jobs:
PR:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sanitizer: [address]
steps:
- name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
with:
sanitizer: ${{ matrix.sanitizer }}
language: c++
bad-build-check: false
- name: Run Fuzzers (${{ matrix.sanitizer }})
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 240
mode: 'code-change'
report-unreproducible-crashes: false
sanitizer: ${{ matrix.sanitizer }}

View File

@@ -1,280 +0,0 @@
name: build
on: [push, pull_request]
jobs:
build-linux-gcc:
runs-on: Ubuntu-22.04
strategy:
matrix:
compiler: ['g++-12', 'g++-11', 'g++-10', 'g++-9']
standard: ['11', '14', '17', '20']
unreleased: ['ON', 'OFF']
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install libboost-test-dev
sudo apt-get install language-pack-fr # test serializer w/ locale
sudo apt-get install ${{ matrix.compiler }}
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-linux-clang:
runs-on: Ubuntu-22.04
strategy:
matrix:
compiler: ['15', '14', '13', '12', '11']
standard: ['11', '14', '17', '20']
unreleased: ['ON', 'OFF']
exclude:
- {compiler: '14', standard: '20'} # to avoid using gcc-13 libstdc++
- {compiler: '13', standard: '20'} # with older clang
- {compiler: '12', standard: '20'}
- {compiler: '11', standard: '20'}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install libboost-test-dev
sudo apt-get install language-pack-fr # test serializer w/ locale
sudo apt-get install clang-${{ matrix.compiler }}
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_C_COMPILER=clang-${{ matrix.compiler }} -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-linux-old-gcc:
runs-on: Ubuntu-20.04
strategy:
matrix:
compiler: ['g++-8', 'g++-7']
standard: ['11', '14', '17', '20']
unreleased: ['ON', 'OFF']
exclude:
- {compiler: 'g++-7', standard: '20'}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install libboost-test-dev
sudo apt-get install language-pack-fr # test serializer w/ locale
sudo apt-get install ${{ matrix.compiler }}
- name: Configure
run: |
mkdir build && cd build
if [[ "${{ matrix.compiler }}" == "g++-8" && ( "${{ matrix.standard }}" == "17" || "${{ matrix.standard }}" == "20" ) ]] ; then
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_REQUIRE_FILESYSTEM_LIBRARY=ON -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
else
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
fi
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-linux-old-clang:
runs-on: Ubuntu-20.04
strategy:
matrix:
compiler: ['10', '9', '8', '7', '6.0']
standard: ['11', '14', '17', '20']
unreleased: ['ON', 'OFF']
exclude:
- {compiler: '6.0', standard: '20'}
- {compiler: '7', standard: '20'}
- {compiler: '8', standard: '20'}
- {compiler: '9', standard: '20'}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install libboost-test-dev
sudo apt-get install language-pack-fr # test serializer w/ locale
sudo apt-get install clang-${{ matrix.compiler }}
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_C_COMPILER=clang-${{ matrix.compiler }} -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
# build-osx-13-arm64:
# runs-on: macos-13-arm64
# strategy:
# matrix:
# standard: ['11', '14', '17', '20']
# unreleased: ['ON', 'OFF']
# steps:
# - name: Checkout
# uses: actions/checkout@v3
# with:
# submodules: true
# - name: Install
# run: |
# brew install boost
# - name: Configure
# run: |
# mkdir build && cd build
# cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
# - name: Build
# run: |
# cd build && cmake --build .
# - name: Test
# run: |
# cd build && ctest --output-on-failure
build-osx-13:
runs-on: macos-13
strategy:
matrix:
standard: ['11', '14', '17', '20']
unreleased: ['ON', 'OFF']
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
brew install boost
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-osx-12:
runs-on: macos-12
strategy:
matrix:
standard: ['11', '14', '17', '20']
unreleased: ['ON', 'OFF']
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
brew install boost
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-osx-11:
runs-on: macos-11
strategy:
matrix:
standard: ['11', '14', '17', '20']
unreleased: ['ON', 'OFF']
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
brew install boost
- name: Configure
run: |
mkdir build && cd build
cmake .. -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
- name: Build
run: |
cd build && cmake --build .
- name: Test
run: |
cd build && ctest --output-on-failure
build-windows-msvc:
runs-on: windows-2022
strategy:
matrix:
standard: ['11', '14', '17', '20']
config: ['Release', 'Debug']
unreleased: ['ON', 'OFF']
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install
run: |
(New-Object System.Net.WebClient).DownloadFile("https://github.com/actions/boost-versions/releases/download/1.72.0-20200608.4/boost-1.72.0-win32-msvc14.2-x86_64.tar.gz", "$env:TEMP\\boost.tar.gz")
7z.exe x "$env:TEMP\\boost.tar.gz" -o"$env:TEMP\\boostArchive" -y | Out-Null
7z.exe x "$env:TEMP\\boostArchive" -o"$env:TEMP\\boost" -y | Out-Null
Push-Location -Path "$env:TEMP\\boost"
Invoke-Expression .\\setup.ps1
- uses: ilammy/msvc-dev-cmd@v1
- name: Configure
shell: cmd
run: |
file --mime-encoding tests/test_literals.cpp
mkdir build
cd build
cmake ../ -G "NMake Makefiles" -Dtoml11_BUILD_TEST=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DBoost_NO_BOOST_CMAKE=ON -DBOOST_ROOT="C:\\hostedtoolcache\\windows\\Boost\\1.72.0\\x86_64" -DTOML11_USE_UNRELEASED_TOML_FEATURES=${{ matrix.unreleased }}
- name: Build
working-directory: ./build
run: |
cmake --build . --config "${{ matrix.config }}"
- name: Test
working-directory: ./build
run: |
file --mime-encoding tests/toml/tests/example.toml
file --mime-encoding tests/toml/tests/fruit.toml
file --mime-encoding tests/toml/tests/hard_example.toml
file --mime-encoding tests/toml/tests/hard_example_unicode.toml
ctest --build-config "${{ matrix.config }}" --output-on-failure

184
.travis.yml Normal file
View File

@@ -0,0 +1,184 @@
dist: trusty
matrix:
include:
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-5" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-5
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-6" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-6
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-7" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-7
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8" CXX_STANDARD=17
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-3.7" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- clang-3.7
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-4.0" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- clang-4.0
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-5.0" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- clang-5.0
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-6.0" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-6.0
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- clang-6.0
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-7" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-7
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- clang-7
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=11
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- g++-8
- clang-8
- boost1.70
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8" CXX_STANDARD=17
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- clang-8
- g++-8
- boost1.70
- os: osx
language: cpp
compiler: clang
env: CXX_STANDARD=11
script:
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
mkdir -p cmake
travis_retry wget "https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz"
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
else
brew upgrade cmake boost
fi
- cmake --version
- mkdir build
- cd build
- git clone https://github.com/toml-lang/toml.git
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD ..
- make
- ctest --output-on-failure

View File

@@ -1,25 +1,24 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 2.8)
enable_testing()
project(toml11 VERSION 3.8.0)
project(toml11)
option(toml11_BUILD_TEST "Build toml tests" OFF)
option(toml11_INSTALL "Install CMake targets during install step." ON)
option(toml11_TEST_WITH_ASAN "use LLVM address sanitizer" OFF)
option(toml11_TEST_WITH_UBSAN "use LLVM undefined behavior sanitizer" OFF)
set(toml11_VERSION_MAYOR 3)
set(toml11_VERSION_MINOR 0)
set(toml11_VERSION_PATCH 1)
set(toml11_VERSION
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
)
option(TOML11_USE_UNRELEASED_TOML_FEATURES
"use features in toml-lang/toml master while testing" OFF)
option(toml11_BUILD_TEST "Build toml tests" ON)
include(CheckCXXCompilerFlag)
if("${CMAKE_VERSION}" VERSION_GREATER 3.1)
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Boolean specifying whether compiler specific extensions are requested.")
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT DEFINED CMAKE_CXX_STANDARD)
message(FATAL_ERROR "CMAKE_CXX_STANDARD is not defined. \
The C++ standard whose features are requested to *build* all targets. \
Remember that toml11 is a header only library that does NOT require compilation to use.")
set(CMAKE_CXX_STANDARD 11)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Boolean describing whether the value of CXX_STANDARD is a requirement.")
set(CXX_STANDARD_REQUIRED ON)
else()
# Manually check for C++11 compiler flag.
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
@@ -45,19 +44,6 @@ else()
endif()
endif()
if(MSVC)
# add_definitions("/Zc:__cplusplus") # define __cplusplus value correctly
add_definitions("/utf-8") # enable to use u8"" literal
if(MSVC_VERSION LESS 1910)
message(STATUS "MSVC < 1910. DEFINE_CONVERSION_NON_INTRUSIVE is disabled")
add_definitions(-DTOML11_WITHOUT_DEFINE_NON_INTRUSIVE)
elseif(MSVC_VERSION LESS 1920)
add_definitions("/experimental:preprocessor") # MSVC 2017
else()
add_definitions("/Zc:preprocessor") # MSVC 2019
endif()
endif()
# Set some common directories
include(GNUInstallDirs)
set(toml11_install_cmake_dir ${CMAKE_INSTALL_LIBDIR}/cmake/toml11)
@@ -81,40 +67,38 @@ write_basic_package_version_file(
COMPATIBILITY SameMajorVersion
)
if (toml11_INSTALL)
configure_package_config_file(
configure_package_config_file(
cmake/toml11Config.cmake.in
${toml11_config}
INSTALL_DESTINATION ${toml11_install_cmake_dir}
PATH_VARS toml11_install_cmake_dir
)
)
# Install config files
install(FILES ${toml11_config} ${toml11_config_version}
# Install config files
install(FILES ${toml11_config} ${toml11_config_version}
DESTINATION ${toml11_install_cmake_dir}
)
)
# Install header files
install(
# Install header files
install(
FILES toml.hpp
DESTINATION "${toml11_install_include_dir}"
)
install(
)
install(
DIRECTORY "toml"
DESTINATION "${toml11_install_include_dir}"
FILES_MATCHING PATTERN "*.hpp"
)
)
# Export targets and install them
install(TARGETS toml11
# Export targets and install them
install(TARGETS toml11
EXPORT toml11Targets
)
install(EXPORT toml11Targets
)
install(EXPORT toml11Targets
FILE toml11Targets.cmake
DESTINATION ${toml11_install_cmake_dir}
NAMESPACE toml11::
)
endif()
)
if (toml11_BUILD_TEST)
add_subdirectory(tests)

854
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -17,9 +17,10 @@ build_script:
- cd C:\toml11
- mkdir build
- cd build
- cmake -G"%generator%" -DCMAKE_CXX_STANDARD=11 -DBOOST_ROOT=C:/Libraries/boost_1_69_0 -Dtoml11_BUILD_TEST=ON ..
- git clone https://github.com/toml-lang/toml.git
- file --mime-encoding toml/tests/hard_example_unicode.toml
- cmake -G"%generator%" -DBOOST_ROOT=C:/Libraries/boost_1_69_0 ..
- cmake --build . --config "%configuration%"
- file --mime-encoding tests/toml/tests/hard_example_unicode.toml
test_script:
- ctest --build-config "%configuration%" --timeout 300 --output-on-failure

View File

@@ -1,21 +1,3 @@
include(ExternalProject)
set(TOML11_LANGSPEC_GIT_REPOSITORY "https://github.com/toml-lang/toml" CACHE STRING
"URL of the TOML language specification repository")
set(TOML11_LANGSPEC_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/toml" CACHE FILEPATH
"directory for the TOML language specification tree")
if(NOT EXISTS "${TOML11_LANGSPEC_SOURCE_DIR}/toml.abnf")
ExternalProject_Add(toml
SOURCE_DIR "${TOML11_LANGSPEC_SOURCE_DIR}"
GIT_REPOSITORY "${TOML11_LANGSPEC_GIT_REPOSITORY}"
GIT_TAG "v0.5.0"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
endif()
set(TEST_NAMES
test_datetime
test_string
@@ -45,7 +27,7 @@ set(TEST_NAMES
test_get_or
test_find
test_find_or
test_find_or_recursive
test_find_fuzzy
test_expect
test_parse_file
test_serialize_file
@@ -58,94 +40,6 @@ set(TEST_NAMES
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
CHECK_CXX_COMPILER_FLAG("-Wextra" COMPILER_SUPPORTS_WEXTRA)
CHECK_CXX_COMPILER_FLAG("-Wpedantic" COMPILER_SUPPORTS_WPEDANTIC)
CHECK_CXX_COMPILER_FLAG("-Werror" COMPILER_SUPPORTS_WERROR)
CHECK_CXX_COMPILER_FLAG("-Wsign-conversion" COMPILER_SUPPORTS_WSIGN_CONVERSION)
CHECK_CXX_COMPILER_FLAG("-Wconversion" COMPILER_SUPPORTS_WCONVERSION)
CHECK_CXX_COMPILER_FLAG("-Wduplicated-cond" COMPILER_SUPPORTS_WDUPLICATED_COND)
CHECK_CXX_COMPILER_FLAG("-Wduplicated-branches" COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
CHECK_CXX_COMPILER_FLAG("-Wlogical-op" COMPILER_SUPPORTS_WLOGICAL_OP)
CHECK_CXX_COMPILER_FLAG("-Wuseless-cast" COMPILER_SUPPORTS_WUSELESS_CAST)
CHECK_CXX_COMPILER_FLAG("-Wdouble-promotion" COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
CHECK_CXX_COMPILER_FLAG("-Wrange-loop-analysis" COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
CHECK_CXX_COMPILER_FLAG("-Wundef" COMPILER_SUPPORTS_WUNDEF)
CHECK_CXX_COMPILER_FLAG("-Wshadow" COMPILER_SUPPORTS_WSHADOW)
include(CheckCXXSourceCompiles)
# check which standard library implementation is used. If libstdc++ is used,
# it will fail to compile. It compiles if libc++ is used.
check_cxx_source_compiles("
#include <cstddef>
#ifdef __GLIBCXX__
static_assert(false);
#endif
int main() {
return 0;
}" TOML11_WITH_LIBCXX_LIBRARY)
# LLVM 8 requires -lc++fs if compiled with libc++ to use <filesystem>.
# LLVM 9+ does not require any special library.
# GCC 8 requires -lstdc++fs. GCC 9+ does not require it.
#
# Yes, we can check the version of the compiler used in the current build
# directly in CMake. But, in most cases, clang build uses libstdc++ as the
# standard library implementation and it makes the condition complicated.
# In many environment, the default installed C++ compiler is GCC and libstdc++
# is installed along with it. In most build on such an environment, even if we
# chose clang as the C++ compiler, still libstdc++ is used. Checking default
# gcc version makes the condition complicated.
# The purpose of this file is to compile tests. We know the environment on which
# the tests run. We can set this option and, I think, it is easier and better.
option(TOML11_REQUIRE_FILESYSTEM_LIBRARY "need to link -lstdc++fs or -lc++fs" OFF)
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
set(PREVIOUSLY_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}")
set(PREVIOUSLY_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}")
list(APPEND CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
check_cxx_source_compiles("
#define BOOST_TEST_MODULE \"dummy\"
#undef BOOST_TEST_DYN_LINK
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); }
" TOML11_WITH_BOOST_TEST_HEADER)
check_cxx_source_compiles("
#define BOOST_TEST_MODULE \"dummy\"
#undef BOOST_TEST_DYN_LINK
#undef BOOST_TEST_NO_LIB
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); }
" TOML11_WITH_BOOST_TEST_STATIC)
check_cxx_source_compiles("
#define BOOST_TEST_MODULE \"dummy\"
#define BOOST_TEST_DYN_LINK
#undef BOOST_TEST_NO_LIB
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(proforma) { BOOST_TEST(true); }
" TOML11_WITH_BOOST_TEST_DYNAMIC)
set(CMAKE_REQUIRED_INCLUDES "${PREVIOUSLY_REQUIRED_INCLUDES}")
set(CMAKE_REQUIRED_LIBRARIES "${PREVIOUSLY_REQUIRED_LIBRARIES}")
unset(PREVIOUSLY_REQUIRED_INCLUDES)
unset(PREVIOUSLY_REQUIRED_LIBRARIES)
if(TOML11_WITH_BOOST_TEST_DYNAMIC)
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST -DBOOST_TEST_DYN_LINK)
elseif(TOML11_WITH_BOOST_TEST_STATIC)
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
elseif(TOML11_WITH_BOOST_TEST_HEADER)
add_definitions(-DBOOST_TEST_NO_LIB)
else()
message(FATAL_ERROR "Neither the Boost.Test static or shared library nor the header-only version seem to be usable.")
endif()
if(COMPILER_SUPPORTS_WALL)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
@@ -156,44 +50,6 @@ endif()
if(COMPILER_SUPPORTS_WPEDANTIC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
endif()
if(COMPILER_SUPPORTS_WERROR)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
if(COMPILER_SUPPORTS_WSHADOW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
endif()
if(COMPILER_SUPPORTS_WSIGN_CONVERSION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
endif()
if(COMPILER_SUPPORTS_WCONVERSION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
endif()
if(COMPILER_SUPPORTS_WDUPLICATED_COND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-cond")
endif()
if(COMPILER_SUPPORTS_WDUPLICATED_BRANCHES)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wduplicated-branches")
endif()
if(COMPILER_SUPPORTS_WLOGICAL_OP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wlogical-op")
endif()
if(COMPILER_SUPPORTS_WUSELESS_CAST)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wuseless-cast")
endif()
if(COMPILER_SUPPORTS_WDOUBLE_PROMOTION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
endif()
if(COMPILER_SUPPORTS_WRANGE_LOOP_ANALYSIS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wrange-loop-analysis")
endif()
if(COMPILER_SUPPORTS_WUNDEF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wundef")
endif()
if(TOML11_USE_UNRELEASED_TOML_FEATURES)
message(STATUS "adding TOML11_USE_UNRELEASED_TOML_FEATURES flag")
add_definitions("-DTOML11_USE_UNRELEASED_TOML_FEATURES")
endif()
# Disable some MSVC warnings
if(MSVC)
@@ -231,61 +87,29 @@ if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4820")
# pragma warning(pop): likely mismatch, popping warning state pushed in different file
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd5031")
# pragma warning(pop): spectre warnings in tests
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd5045")
# pragma warning(pop): spectre warnings in tests
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4265")
endif()
set(TEST_ENVIRON "TOMLDIR=${TOML11_LANGSPEC_SOURCE_DIR}")
if(WIN32)
# Set the PATH to be able to find Boost DLL
STRING(REPLACE ";" "\\;" PATH_STRING "$ENV{PATH}")
list(APPEND TEST_ENVIRON "PATH=${PATH_STRING}\;${Boost_LIBRARY_DIRS}")
endif()
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
add_definitions(-DBOOST_TEST_DYN_LINK)
add_definitions(-DUNITTEST_FRAMEWORK_LIBRARY_EXIST)
foreach(TEST_NAME ${TEST_NAMES})
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
target_include_directories(${TEST_NAME} SYSTEM PRIVATE ${Boost_INCLUDE_DIRS})
target_compile_definitions(${TEST_NAME} PRIVATE "BOOST_TEST_MODULE=\"${TEST_NAME}\"")
# to compile tests with <filesystem>...
if(TOML11_REQUIRE_FILESYSTEM_LIBRARY)
if(TOML11_WITH_LIBCXX_LIBRARY)
target_link_libraries(${TEST_NAME} "c++fs")
else()
target_link_libraries(${TEST_NAME} "stdc++fs")
endif()
endif()
target_include_directories(${TEST_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(toml11_TEST_WITH_ASAN)
set_target_properties(${TEST_NAME} PROPERTIES
COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer"
LINK_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
elseif(toml11_TEST_WITH_UBSAN)
set_target_properties(${TEST_NAME} PROPERTIES
COMPILE_FLAGS "-fsanitize=undefined"
LINK_FLAGS "-fsanitize=undefined")
# Set the PATH to be able to find Boost DLL
if(WIN32)
STRING(REPLACE ";" "\\;" PATH_STRING "$ENV{PATH}")
set_tests_properties(${TEST_NAME}
PROPERTIES ENVIRONMENT "PATH=${PATH_STRING}\;${Boost_LIBRARY_DIRS}"
)
endif()
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${TEST_ENVIRON}")
endforeach(TEST_NAME)
# this test is to check it compiles. it will not run
add_executable(test_multiple_translation_unit
test_multiple_translation_unit_1.cpp
test_multiple_translation_unit_2.cpp)
target_link_libraries(test_multiple_translation_unit toml11::toml11)
if(WIN32)
add_executable(test_windows test_windows.cpp)
target_link_libraries(test_windows toml11::toml11)
endif()

View File

@@ -1,5 +1,4 @@
#include <toml.hpp>
#include "toml.hpp"
#include <iostream>
#include <iomanip>

View File

@@ -1,7 +1,6 @@
#include <toml.hpp>
#include <iomanip>
#include "toml.hpp"
#include <iostream>
#include <iomanip>
int main(int argc, char **argv)
{
@@ -22,30 +21,6 @@ int main(int argc, char **argv)
const auto serialized = toml::parse("tmp.toml");
if(data != serialized)
{
// this is really a ditry hack, but is the easiest way...
// TODO: cleanup by adding comparison function to check if a value is NaN or not
if(filename.substr(filename.size() - 22, 22) == "float-inf-and-nan.toml" &&
std::isnan (toml::find<double>(serialized, "nan")) &&
!std::signbit (toml::find<double>(serialized, "nan")) &&
std::isnan (toml::find<double>(serialized, "nan_plus")) &&
!std::signbit (toml::find<double>(serialized, "nan_plus")) &&
std::isnan (toml::find<double>(serialized, "nan_neg")) &&
std::signbit (toml::find<double>(serialized, "nan_neg")) &&
!std::isnan (toml::find<double>(serialized, "infinity")) &&
!std::isfinite(toml::find<double>(serialized, "infinity")) &&
!std::signbit (toml::find<double>(serialized, "infinity")) &&
!std::isnan (toml::find<double>(serialized, "infinity_plus")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_plus")) &&
!std::signbit (toml::find<double>(serialized, "infinity_plus")) &&
!std::isnan (toml::find<double>(serialized, "infinity_neg")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_neg")) &&
std::signbit (toml::find<double>(serialized, "infinity_neg")))
{
// then it is correctly serialized.
// Note that, the result of (nan == nan) is false. so `data == serialized` is false.
}
else
{
std::cerr << "============================================================\n";
std::cerr << "result (w/o comment) different: " << filename << std::endl;
@@ -58,7 +33,6 @@ int main(int argc, char **argv)
return 1;
}
}
}
{
const auto data = toml::parse<toml::preserve_comments>(filename);
{
@@ -67,36 +41,6 @@ int main(int argc, char **argv)
}
const auto serialized = toml::parse<toml::preserve_comments>("tmp.toml");
if(data != serialized)
{
// this is really a ditry hack, but is the easiest way...
// TODO: cleanup by adding comparison function to check if a value is NaN or not
if(filename.substr(filename.size() - 22, 22) == "float-inf-and-nan.toml" &&
std::isnan (toml::find<double>(serialized, "nan")) &&
!std::signbit (toml::find<double>(serialized, "nan")) &&
std::isnan (toml::find<double>(serialized, "nan_plus")) &&
!std::signbit (toml::find<double>(serialized, "nan_plus")) &&
std::isnan (toml::find<double>(serialized, "nan_neg")) &&
std::signbit (toml::find<double>(serialized, "nan_neg")) &&
!std::isnan (toml::find<double>(serialized, "infinity")) &&
!std::isfinite(toml::find<double>(serialized, "infinity")) &&
!std::signbit (toml::find<double>(serialized, "infinity")) &&
!std::isnan (toml::find<double>(serialized, "infinity_plus")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_plus")) &&
!std::signbit (toml::find<double>(serialized, "infinity_plus")) &&
!std::isnan (toml::find<double>(serialized, "infinity_neg")) &&
!std::isfinite(toml::find<double>(serialized, "infinity_neg")) &&
std::signbit (toml::find<double>(serialized, "infinity_neg")) &&
toml::find(data, "nan").comments() == toml::find(serialized, "nan").comments() &&
toml::find(data, "nan_plus").comments() == toml::find(serialized, "nan_plus").comments() &&
toml::find(data, "nan_neg").comments() == toml::find(serialized, "nan_neg").comments() &&
toml::find(data, "infinity").comments() == toml::find(serialized, "infinity").comments() &&
toml::find(data, "infinity_plus").comments() == toml::find(serialized, "infinity_plus").comments() &&
toml::find(data, "infinity_neg").comments() == toml::find(serialized, "infinity_neg").comments() )
{
// then it is correctly serialized.
// Note that, the result of (nan == nan) is false. so `data == serialized` is false.
}
else
{
std::cerr << "============================================================\n";
std::cerr << "result (w/ comment) different: " << filename << std::endl;
@@ -109,6 +53,5 @@ int main(int argc, char **argv)
return 1;
}
}
}
return 0;
}

View File

@@ -1,7 +1,6 @@
#include <toml.hpp>
#include <iomanip>
#include "toml.hpp"
#include <iostream>
#include <iomanip>
struct json_serializer
{
@@ -17,14 +16,6 @@ struct json_serializer
}
void operator()(toml::floating v)
{
if(std::isnan(v) && std::signbit(v))
{
// toml-test does not allow negative NaN represented in "-nan" because
// there are languages that does not distinguish nan and -nan.
// But toml11 keeps sign from input. To resolve this difference,
// we convert -nan to nan here.
v = std::numeric_limits<toml::floating>::quiet_NaN();
}
std::cout << "{\"type\":\"float\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
@@ -33,24 +24,23 @@ struct json_serializer
// since toml11 automatically convert string to multiline string that is
// valid only in TOML, we need to format the string to make it valid in
// JSON.
toml::serializer<toml::value> ser(std::numeric_limits<std::size_t>::max());
std::cout << "{\"type\":\"string\",\"value\":"
<< ser(v.str) << "}";
std::cout << "{\"type\":\"string\",\"value\":\""
<< this->escape_string(v.str) << "\"}";
return ;
}
void operator()(const toml::local_time& v)
{
std::cout << "{\"type\":\"time-local\",\"value\":\"" << toml::value(v) << "\"}";
std::cout << "{\"type\":\"local_time\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::local_date& v)
{
std::cout << "{\"type\":\"date-local\",\"value\":\"" << toml::value(v) << "\"}";
std::cout << "{\"type\":\"local_date\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::local_datetime& v)
{
std::cout << "{\"type\":\"datetime-local\",\"value\":\"" << toml::value(v) << "\"}";
std::cout << "{\"type\":\"local_datetime\",\"value\":\"" << toml::value(v) << "\"}";
return ;
}
void operator()(const toml::offset_datetime& v)
@@ -74,8 +64,7 @@ struct json_serializer
}
else
{
// std::cout << "{\"type\":\"array\",\"value\":[";
std::cout << "[";
std::cout << "{\"type\":\"array\",\"value\":[";
bool is_first = true;
for(const auto& elem : v)
{
@@ -83,7 +72,7 @@ struct json_serializer
is_first = false;
toml::visit(*this, elem);
}
std::cout << "]";
std::cout << "]}";
}
return ;
}
@@ -95,20 +84,34 @@ struct json_serializer
{
if(!is_first) {std::cout << ", ";}
is_first = false;
const auto k = toml::format_key(elem.first);
if(k.at(0) == '"')
{
std::cout << k << ":";
}
else // bare key
{
std::cout << '\"' << k << "\":";
}
std::cout << toml::format(toml::value(elem.first),
std::numeric_limits<std::size_t>::max());
std::cout << ':';
toml::visit(*this, elem.second);
}
std::cout << '}';
return ;
}
std::string escape_string(const std::string& s) const
{
std::string retval;
for(const char c : s)
{
switch(c)
{
case '\\': {retval += "\\\\"; break;}
case '\"': {retval += "\\\""; break;}
case '\b': {retval += "\\b"; break;}
case '\t': {retval += "\\t"; break;}
case '\f': {retval += "\\f"; break;}
case '\n': {retval += "\\n"; break;}
case '\r': {retval += "\\r"; break;}
default : {retval += c; break;}
}
}
return retval;
}
};
int main()

View File

@@ -1,11 +1,17 @@
#include <toml.hpp>
#define BOOST_TEST_MODULE "test_comments"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include "unit_test.hpp"
#include <toml.hpp>
BOOST_AUTO_TEST_CASE(test_comment_before)
{
{
const std::string file = R"(
const std::string file = u8R"(
# comment for a.
a = 42
# comment for b.
@@ -18,12 +24,12 @@ BOOST_AUTO_TEST_CASE(test_comment_before)
const auto& b = toml::find(v, "b");
BOOST_TEST(a.comments().size() == 1u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(a.comments().front() == u8" comment for a.");
BOOST_TEST(b.comments().size() == 1u);
BOOST_TEST(b.comments().front() == " comment for b.");
BOOST_TEST(b.comments().front() == u8" comment for b.");
}
{
const std::string file = R"(
const std::string file = u8R"(
# comment for a.
# another comment for a.
a = 42
@@ -39,18 +45,18 @@ BOOST_AUTO_TEST_CASE(test_comment_before)
const auto& b = toml::find(v, "b");
BOOST_TEST(a.comments().size() == 2u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(a.comments().back() == " another comment for a.");
BOOST_TEST(a.comments().front() == u8" comment for a.");
BOOST_TEST(a.comments().back() == u8" another comment for a.");
BOOST_TEST(b.comments().size() == 2u);
BOOST_TEST(b.comments().front() == " comment for b.");
BOOST_TEST(b.comments().back() == " also comment for b.");
BOOST_TEST(b.comments().front() == u8" comment for b.");
BOOST_TEST(b.comments().back() == u8" also comment for b.");
}
}
BOOST_AUTO_TEST_CASE(test_comment_inline)
{
{
const std::string file = R"(
const std::string file = u8R"(
a = 42 # comment for a.
b = "baz" # comment for b.
)";
@@ -62,12 +68,12 @@ BOOST_AUTO_TEST_CASE(test_comment_inline)
const auto& b = toml::find(v, "b");
BOOST_TEST(a.comments().size() == 1u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(a.comments().front() == u8" comment for a.");
BOOST_TEST(b.comments().size() == 1u);
BOOST_TEST(b.comments().front() == " comment for b.");
BOOST_TEST(b.comments().front() == u8" comment for b.");
}
{
const std::string file = R"(
const std::string file = u8R"(
a = [
42,
] # comment for a.
@@ -84,18 +90,18 @@ BOOST_AUTO_TEST_CASE(test_comment_inline)
const auto& b0 = b.as_array().at(0);
BOOST_TEST(a.comments().size() == 1u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(a.comments().front() == u8" comment for a.");
BOOST_TEST(b.comments().size() == 1u);
BOOST_TEST(b.comments().front() == " this is a comment for b.");
BOOST_TEST(b.comments().front() == u8" this is a comment for b.");
BOOST_TEST(b0.comments().size() == 1u);
BOOST_TEST(b0.comments().front() == " this is not a comment for b, but \"bar\"");
BOOST_TEST(b0.comments().front() == u8" this is not a comment for b, but \"bar\"");
}
}
BOOST_AUTO_TEST_CASE(test_comment_both)
{
{
const std::string file = R"(
const std::string file = u8R"(
# comment for a.
a = 42 # inline comment for a.
# comment for b.
@@ -116,62 +122,25 @@ BOOST_AUTO_TEST_CASE(test_comment_both)
const auto& c0 = c.as_array().at(0);
BOOST_TEST(a.comments().size() == 2u);
BOOST_TEST(a.comments().front() == " comment for a.");
BOOST_TEST(a.comments().back() == " inline comment for a.");
BOOST_TEST(a.comments().front() == u8" comment for a.");
BOOST_TEST(a.comments().back() == u8" inline comment for a.");
BOOST_TEST(b.comments().size() == 2u);
BOOST_TEST(b.comments().front() == " comment for b.");
BOOST_TEST(b.comments().back() == " inline comment for b.");
BOOST_TEST(b.comments().front() == u8" comment for b.");
BOOST_TEST(b.comments().back() == u8" inline comment for b.");
BOOST_TEST(c.comments().size() == 2u);
BOOST_TEST(c.comments().front() == " comment for c.");
BOOST_TEST(c.comments().back() == " another comment for c.");
BOOST_TEST(c.comments().front() == u8" comment for c.");
BOOST_TEST(c.comments().back() == u8" another comment for c.");
BOOST_TEST(c0.comments().size() == 2u);
BOOST_TEST(c0.comments().front() == " comment for the first element.");
BOOST_TEST(c0.comments().back() == " this also.");
}
}
BOOST_AUTO_TEST_CASE(test_comments_on_implicit_values)
{
{
const std::string file = R"(
# comment for the first element of array-of-tables.
[[array-of-tables]]
foo = "bar"
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto aot = toml::find(v, "array-of-tables");
const auto elm = aot.at(0);
BOOST_TEST(aot.comments().empty());
BOOST_TEST(elm.comments().size() == 1);
BOOST_TEST(elm.comments().front() == " comment for the first element of array-of-tables.");
}
{
const std::string file = R"(
# comment for the array itself
array-of-tables = [
# comment for the first element of array-of-tables.
{foo = "bar"}
]
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::preserve_comments>(iss);
const auto aot = toml::find(v, "array-of-tables");
const auto elm = aot.at(0);
BOOST_TEST(aot.comments().size() == 1);
BOOST_TEST(aot.comments().front() == " comment for the array itself");
BOOST_TEST(elm.comments().size() == 1);
BOOST_TEST(elm.comments().front() == " comment for the first element of array-of-tables.");
BOOST_TEST(c0.comments().front() == u8" comment for the first element.");
BOOST_TEST(c0.comments().back() == u8" this also.");
}
}
BOOST_AUTO_TEST_CASE(test_discard_comment)
{
const std::string file = R"(
const std::string file = u8R"(
# comment for a.
a = 42 # inline comment for a.
# comment for b.
@@ -184,7 +153,7 @@ BOOST_AUTO_TEST_CASE(test_discard_comment)
)";
std::istringstream iss(file);
const auto v = toml::parse<toml::discard_comments>(iss);
const auto v = toml::parse(iss);
const auto& a = toml::find(v, "a");
const auto& b = toml::find(v, "b");
@@ -266,7 +235,7 @@ BOOST_AUTO_TEST_CASE(test_construct_value_with_comments)
BOOST_TEST(v.is_string());
BOOST_TEST(v.as_string() == "str");
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __cplusplus >= 201703L
{
using namespace std::literals::string_view_literals;
const value_type v("str"sv, {"comment1", "comment2"});

View File

@@ -1,7 +1,12 @@
#define BOOST_TEST_MODULE "test_datetime"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/datetime.hpp>
#include "unit_test.hpp"
BOOST_AUTO_TEST_CASE(test_local_date)
{
const toml::local_date date(2018, toml::month_t::Jan, 1);

View File

@@ -1,9 +1,13 @@
#define BOOST_TEST_MODULE "test_error_detection"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <fstream>
#include <iostream>
#include <fstream>
BOOST_AUTO_TEST_CASE(test_detect_empty_key)
{
@@ -76,14 +80,10 @@ BOOST_AUTO_TEST_CASE(test_detect_conflicting_value)
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
{
#ifdef TOML11_DISALLOW_HETEROGENEOUS_ARRAYS
std::istringstream stream(std::string(
"a = [1, 1.0]\n"
));
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
#else
BOOST_TEST_MESSAGE("After v1.0.0-rc.1, heterogeneous arrays are allowed");
#endif
}
BOOST_AUTO_TEST_CASE(test_detect_appending_array_of_table)

View File

@@ -1,12 +1,16 @@
#define BOOST_TEST_MODULE "test_expect"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <array>
#include <deque>
#include <list>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
BOOST_AUTO_TEST_CASE(test_expect)
{

View File

@@ -1,7 +1,11 @@
#define BOOST_TEST_MODULE "test_extended_conversions"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <deque>
#include <map>
@@ -29,27 +33,6 @@ struct bar
return toml::table{{"a", this->a}, {"b", this->b}};
}
};
struct baz
{
int a;
std::string b;
};
struct qux
{
int a;
std::string b;
};
struct foobar
{
// via constructor
explicit foobar(const toml::value& v)
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
{}
int a;
std::string b;
};
} // extlib
namespace toml
@@ -66,25 +49,7 @@ struct from<extlib::foo>
template<>
struct into<extlib::foo>
{
static toml::value into_toml(const extlib::foo& f)
{
return toml::value{{"a", f.a}, {"b", f.b}};
}
};
template<>
struct from<extlib::baz>
{
static extlib::baz from_toml(const toml::value& v)
{
return extlib::baz{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
}
};
template<>
struct into<extlib::qux>
{
static toml::table into_toml(const extlib::qux& f)
static toml::table into_toml(const extlib::foo& f)
{
return toml::table{{"a", f.a}, {"b", f.b}};
}
@@ -118,27 +83,6 @@ struct bar
return toml::table{{"a", this->a}, {"b", this->b}};
}
};
struct baz
{
int a;
std::string b;
};
struct qux
{
int a;
std::string b;
};
struct foobar
{
template<typename C, template<typename ...> class M, template<typename ...> class A>
explicit foobar(const toml::basic_value<C, M, A>& v)
: a(toml::find<int>(v, "a")), b(toml::find<std::string>(v, "b"))
{}
int a;
std::string b;
};
} // extlib2
namespace toml
@@ -161,28 +105,6 @@ struct into<extlib2::foo>
return toml::table{{"a", f.a}, {"b", f.b}};
}
};
template<>
struct from<extlib2::baz>
{
template<typename C, template<typename ...> class M, template<typename ...> class A>
static extlib2::baz from_toml(const toml::basic_value<C, M, A>& v)
{
return extlib2::baz{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
}
};
template<>
struct into<extlib2::qux>
{
static toml::basic_value<toml::preserve_comments, std::map>
into_toml(const extlib2::qux& f)
{
return toml::basic_value<toml::preserve_comments, std::map>{
{"a", f.a}, {"b", f.b}
};
}
};
} // toml
// ---------------------------------------------------------------------------
@@ -266,62 +188,6 @@ BOOST_AUTO_TEST_CASE(test_conversion_by_specialization)
}
}
BOOST_AUTO_TEST_CASE(test_conversion_one_way)
{
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto baz = toml::get<extlib::baz>(v);
BOOST_TEST(baz.a == 42);
BOOST_TEST(baz.b == "baz");
}
{
const extlib::qux q{42, "qux"};
const toml::value v(q);
BOOST_TEST(toml::find<int>(v, "a") == 42);
BOOST_TEST(toml::find<std::string>(v, "b") == "qux");
}
{
const toml::basic_value<toml::discard_comments, std::map> v{
{"a", 42}, {"b", "baz"}
};
const auto baz = toml::get<extlib2::baz>(v);
BOOST_TEST(baz.a == 42);
BOOST_TEST(baz.b == "baz");
}
{
const extlib::qux q{42, "qux"};
const toml::basic_value<toml::preserve_comments, std::map> v(q);
BOOST_TEST(toml::find<int>(v, "a") == 42);
BOOST_TEST(toml::find<std::string>(v, "b") == "qux");
}
}
BOOST_AUTO_TEST_CASE(test_conversion_via_constructor)
{
{
const toml::value v{{"a", 42}, {"b", "foobar"}};
const auto foobar = toml::get<extlib::foobar>(v);
BOOST_TEST(foobar.a == 42);
BOOST_TEST(foobar.b == "foobar");
}
{
const toml::basic_value<toml::discard_comments, std::map> v{
{"a", 42}, {"b", "foobar"}
};
const auto foobar = toml::get<extlib2::foobar>(v);
BOOST_TEST(foobar.a == 42);
BOOST_TEST(foobar.b == "foobar");
}
}
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
{
{
@@ -422,206 +288,5 @@ BOOST_AUTO_TEST_CASE(test_recursive_conversion)
BOOST_TEST(bars.at(2).b == "quux");
BOOST_TEST(bars.at(3).b == "foobar");
}
// via constructor
{
const toml::value v{
toml::table{{"a", 42}, {"b", "baz"}},
toml::table{{"a", 43}, {"b", "qux"}},
toml::table{{"a", 44}, {"b", "quux"}},
toml::table{{"a", 45}, {"b", "foobar"}}
};
{
const auto foobars = toml::get<std::vector<extlib::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
{
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque>
v{
toml::table{{"a", 42}, {"b", "baz"}},
toml::table{{"a", 43}, {"b", "qux"}},
toml::table{{"a", 44}, {"b", "quux"}},
toml::table{{"a", 45}, {"b", "foobar"}}
};
const auto foobars = toml::get<std::vector<extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at(0).a == 42);
BOOST_TEST(foobars.at(1).a == 43);
BOOST_TEST(foobars.at(2).a == 44);
BOOST_TEST(foobars.at(3).a == 45);
BOOST_TEST(foobars.at(0).b == "baz");
BOOST_TEST(foobars.at(1).b == "qux");
BOOST_TEST(foobars.at(2).b == "quux");
BOOST_TEST(foobars.at(3).b == "foobar");
}
// via constructor
{
const toml::value v{
{"0", toml::table{{"a", 42}, {"b", "baz"}}},
{"1", toml::table{{"a", 43}, {"b", "qux"}}},
{"2", toml::table{{"a", 44}, {"b", "quux"}}},
{"3", toml::table{{"a", 45}, {"b", "foobar"}}}
};
{
const auto foobars = toml::get<std::map<std::string, extlib::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at("0").a == 42);
BOOST_TEST(foobars.at("1").a == 43);
BOOST_TEST(foobars.at("2").a == 44);
BOOST_TEST(foobars.at("3").a == 45);
BOOST_TEST(foobars.at("0").b == "baz");
BOOST_TEST(foobars.at("1").b == "qux");
BOOST_TEST(foobars.at("2").b == "quux");
BOOST_TEST(foobars.at("3").b == "foobar");
}
{
const auto foobars = toml::get<std::map<std::string, extlib2::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at("0").a == 42);
BOOST_TEST(foobars.at("1").a == 43);
BOOST_TEST(foobars.at("2").a == 44);
BOOST_TEST(foobars.at("3").a == 45);
BOOST_TEST(foobars.at("0").b == "baz");
BOOST_TEST(foobars.at("1").b == "qux");
BOOST_TEST(foobars.at("2").b == "quux");
BOOST_TEST(foobars.at("3").b == "foobar");
}
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque>
v{
{"0", toml::table{{"a", 42}, {"b", "baz"}}},
{"1", toml::table{{"a", 43}, {"b", "qux"}}},
{"2", toml::table{{"a", 44}, {"b", "quux"}}},
{"3", toml::table{{"a", 45}, {"b", "foobar"}}}
};
const auto foobars = toml::get<std::map<std::string, extlib::foobar>>(v);
BOOST_TEST(foobars.size() == 4ul);
BOOST_TEST(foobars.at("0").a == 42);
BOOST_TEST(foobars.at("1").a == 43);
BOOST_TEST(foobars.at("2").a == 44);
BOOST_TEST(foobars.at("3").a == 45);
BOOST_TEST(foobars.at("0").b == "baz");
BOOST_TEST(foobars.at("1").b == "qux");
BOOST_TEST(foobars.at("2").b == "quux");
BOOST_TEST(foobars.at("3").b == "foobar");
}
}
// ===========================================================================
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
namespace extlib3
{
struct foo
{
int a;
std::string b;
};
struct bar
{
int a;
std::string b;
foo f;
};
} // extlib3
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib3::foo, a, b)
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib3::bar, a, b, f)
BOOST_AUTO_TEST_CASE(test_conversion_via_macro)
{
{
const toml::value v{{"a", 42}, {"b", "baz"}};
const auto foo = toml::get<extlib3::foo>(v);
BOOST_TEST(foo.a == 42);
BOOST_TEST(foo.b == "baz");
const toml::value v2(foo);
BOOST_TEST(v2 == v);
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque> v{
{"a", 42}, {"b", "baz"}
};
const auto foo = toml::get<extlib3::foo>(v);
BOOST_TEST(foo.a == 42);
BOOST_TEST(foo.b == "baz");
const toml::basic_value<toml::discard_comments, std::map, std::deque> v2(foo);
BOOST_TEST(v2 == v);
}
// -----------------------------------------------------------------------
{
const toml::value v{
{"a", 42},
{"b", "bar.b"},
{"f", toml::table{{"a", 42}, {"b", "foo.b"}}}
};
const auto bar = toml::get<extlib3::bar>(v);
BOOST_TEST(bar.a == 42);
BOOST_TEST(bar.b == "bar.b");
BOOST_TEST(bar.f.a == 42);
BOOST_TEST(bar.f.b == "foo.b");
const toml::value v2(bar);
BOOST_TEST(v2 == v);
}
{
const toml::basic_value<toml::discard_comments, std::map, std::deque> v{
{"a", 42},
{"b", "bar.b"},
{"f", toml::table{{"a", 42}, {"b", "foo.b"}}}
};
const auto bar = toml::get<extlib3::bar>(v);
BOOST_TEST(bar.a == 42);
BOOST_TEST(bar.b == "bar.b");
BOOST_TEST(bar.f.a == 42);
BOOST_TEST(bar.f.b == "foo.b");
const toml::basic_value<toml::discard_comments, std::map, std::deque> v2(bar);
BOOST_TEST(v2 == v);
}
}
#endif // TOML11_WITHOUT_DEFINE_NON_INTRUSIVE

View File

@@ -1,20 +1,25 @@
#include <toml.hpp>
#define BOOST_TEST_MODULE "test_find"
#include "unit_test.hpp"
#include <array>
#include <deque>
#include <list>
#include <map>
#include <tuple>
#include <unordered_map>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <array>
#if __cplusplus >= 201703L
#include <string_view>
#endif
#include <tuple>
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::value,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
@@ -22,32 +27,6 @@ using test_value_types = std::tuple<
BOOST_AUTO_TEST_CASE(test_find_throws)
{
// -----------------------------------------------------------------------
// const-reference version
{
// value is not a table
const toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, "key"), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
const toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, "key"), toml::type_error);
}
{
// the value corresponding to the key is not found
const toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, "different_key"),
std::out_of_range);
}
{
// the positive control.
const toml::value v{{"key", 42}};
BOOST_TEST(42 == toml::find<int>(v, "key"));
}
// -----------------------------------------------------------------------
// reference version
{
// value is not a table
toml::value v(true);
@@ -69,103 +48,6 @@ BOOST_AUTO_TEST_CASE(test_find_throws)
toml::value v{{"key", 42}};
BOOST_TEST(42 == toml::find<int>(v, "key"));
}
// -----------------------------------------------------------------------
// move version
{
// value is not a table
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), "key"), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), "key"), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{{"key", 42}};
BOOST_CHECK_THROW(toml::find<toml::integer>(std::move(v), "different_key"),
std::out_of_range);
}
{
// the positive control.
toml::value v{{"key", 42}};
BOOST_TEST(42 == toml::find<int>(std::move(v), "key"));
}
}
BOOST_AUTO_TEST_CASE(test_find_array_throws)
{
// -----------------------------------------------------------------------
// const-reference version
{
// value is not an array
const toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
const toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not found
const toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
}
{
// the positive control.
const toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(v, 2));
}
// -----------------------------------------------------------------------
// non-const reference version
{
// value is not an array
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(v, 0), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(v, 6), std::out_of_range);
}
{
// the positive control.
toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(v, 2));
}
// -----------------------------------------------------------------------
// move version
{
// value is not an array
toml::value v(true);
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
}
{
// the value corresponding to the key is not the expected type
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::boolean>(std::move(v), 0), toml::type_error);
}
{
// the value corresponding to the key is not found
toml::value v{1, 2, 3, 4, 5};
BOOST_CHECK_THROW(toml::find<toml::integer>(std::move(v), 6), std::out_of_range);
}
{
// the positive control.
toml::value v{1, 2, 3, 4, 5};
BOOST_TEST(3 == toml::find<int>(std::move(v), 2));
}
}
BOOST_AUTO_TEST_CASE(test_find_recursive)
@@ -192,77 +74,6 @@ BOOST_AUTO_TEST_CASE(test_find_recursive)
auto& num2 = toml::find<toml::integer>(v, a, b, c, d);
num2 = 42;
BOOST_TEST(42 == toml::find<int>(v, a, b, c, d));
auto num3 = toml::find<toml::integer>(v, a, "b", c, "d");
BOOST_TEST(42 == num3);
auto num4 = toml::find<toml::integer>(std::move(v), a, b, c, d);
BOOST_TEST(42 == num4);
}
// recursively search arrays
{
toml::value v{
toml::array{"array", "of", "string"},
toml::array{toml::array{1, 2, 3}, toml::array{3.14, 2.71}}
};
BOOST_TEST("array" == toml::find<std::string>(v, 0, 0));
BOOST_TEST("of" == toml::find<std::string>(v, 0, 1));
BOOST_TEST("string" == toml::find<std::string>(v, 0, 2));
BOOST_TEST(1 == toml::find<int>(v, 1, 0, 0));
BOOST_TEST(2 == toml::find<int>(v, 1, 0, 1));
BOOST_TEST(3 == toml::find<int>(v, 1, 0, 2));
BOOST_TEST(3.14 == toml::find<double>(v, 1, 1, 0));
BOOST_TEST(2.71 == toml::find<double>(v, 1, 1, 1));
// reference that can be used to modify the content
auto& num = toml::find<toml::integer>(v, 1, 0, 2);
num = 42;
BOOST_TEST( 1 == toml::find<int>(v, 1, 0, 0));
BOOST_TEST( 2 == toml::find<int>(v, 1, 0, 1));
BOOST_TEST(42 == toml::find<int>(v, 1, 0, 2));
// move value
auto num2 = toml::find<toml::integer>(std::move(v), 1, 0, 2);
BOOST_TEST(42 == num2);
}
// recursively search mixtures
{
toml::value v = toml::table{{"array", toml::array{
toml::array{1, 2, 3},
toml::array{
toml::table{{"foo", "bar"}, {"baz", "qux"}},
toml::table{{"pi", 3.14}, {"e", 2.71}}
}}
}};
BOOST_TEST(1 == toml::find<int>(v, "array", 0, 0));
BOOST_TEST(2 == toml::find<int>(v, "array", 0, 1));
BOOST_TEST(3 == toml::find<int>(v, "array", 0, 2));
BOOST_TEST("bar" == toml::find<std::string>(v, "array", 1, 0, "foo"));
BOOST_TEST("qux" == toml::find<std::string>(v, "array", 1, 0, "baz"));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, "pi"));
BOOST_TEST(2.71 == toml::find<double>(v, "array", 1, 1, "e"));
const std::string ar("array");
const auto ar_c = "array";
const std::string pi("pi");
const auto pi_c = "pi";
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, "pi"));
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, ar, 1, 1, pi_c));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, "pi"));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, ar_c, 1, 1, pi_c));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi));
BOOST_TEST(3.14 == toml::find<double>(v, "array", 1, 1, pi_c));
}
}
@@ -274,9 +85,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::boolean>(v, "key") = false;
BOOST_TEST(false == toml::find<toml::boolean>(v, "key"));
const auto moved = toml::find<toml::boolean>(std::move(v), "key");
BOOST_TEST(false == moved);
}
{
value_type v{{"key", 42}};
@@ -284,9 +92,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::integer>(v, "key") = 54;
BOOST_TEST(toml::integer(54) == toml::find<toml::integer>(v, "key"));
const auto moved = toml::find<toml::integer>(std::move(v), "key");
BOOST_TEST(toml::integer(54) == moved);
}
{
value_type v{{"key", 3.14}};
@@ -294,9 +99,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::floating>(v, "key") = 2.71;
BOOST_TEST(toml::floating(2.71) == toml::find<toml::floating>(v, "key"));
const auto moved = toml::find<toml::floating>(std::move(v), "key");
BOOST_TEST(toml::floating(2.71) == moved);
}
{
value_type v{{"key", "foo"}};
@@ -306,9 +108,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::string>(v, "key").str += "bar";
BOOST_TEST(toml::string("foobar", toml::string_t::basic) ==
toml::find<toml::string>(v, "key"));
const auto moved = toml::find<toml::string>(std::move(v), "key");
BOOST_TEST(toml::string("foobar", toml::string_t::basic) == moved);
}
{
value_type v{{"key", value_type("foo", toml::string_t::literal)}};
@@ -318,9 +117,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::string>(v, "key").str += "bar";
BOOST_TEST(toml::string("foobar", toml::string_t::literal) ==
toml::find<toml::string>(v, "key"));
const auto moved = toml::find<toml::string>(std::move(v), "key");
BOOST_TEST(toml::string("foobar", toml::string_t::literal) == moved);
}
{
toml::local_date d(2018, toml::month_t::Apr, 22);
@@ -330,9 +126,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::local_date>(v, "key").year = 2017;
d.year = 2017;
BOOST_CHECK(d == toml::find<toml::local_date>(v, "key"));
const auto moved = toml::find<toml::local_date>(std::move(v), "key");
BOOST_CHECK(d == moved);
}
{
toml::local_time t(12, 30, 45);
@@ -342,9 +135,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::local_time>(v, "key").hour = 9;
t.hour = 9;
BOOST_CHECK(t == toml::find<toml::local_time>(v, "key"));
const auto moved = toml::find<toml::local_time>(std::move(v), "key");
BOOST_CHECK(t == moved);
}
{
toml::local_datetime dt(toml::local_date(2018, toml::month_t::Apr, 22),
@@ -355,9 +145,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::local_datetime>(v, "key").date.year = 2017;
dt.date.year = 2017;
BOOST_CHECK(dt == toml::find<toml::local_datetime>(v, "key"));
const auto moved = toml::find<toml::local_datetime>(std::move(v), "key");
BOOST_CHECK(dt == moved);
}
{
toml::offset_datetime dt(toml::local_datetime(
@@ -369,9 +156,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
toml::find<toml::offset_datetime>(v, "key").date.year = 2017;
dt.date.year = 2017;
BOOST_CHECK(dt == toml::find<toml::offset_datetime>(v, "key"));
const auto moved = toml::find<toml::offset_datetime>(std::move(v), "key");
BOOST_CHECK(dt == moved);
}
{
typename value_type::array_type vec;
@@ -387,10 +171,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
const bool result2 = (vec == toml::find<typename value_type::array_type>(v, "key"));
BOOST_CHECK(result2);
const auto moved = toml::find<typename value_type::array_type>(std::move(v), "key");
const bool result3 = (vec == moved);
BOOST_CHECK(result3);
}
{
typename value_type::table_type tab;
@@ -404,10 +184,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
tab["key3"] = value_type(123);
const bool result2 = (tab == toml::find<typename value_type::table_type>(v, "key"));
BOOST_CHECK(result2);
const auto moved = toml::find<typename value_type::table_type>(std::move(v), "key");
const bool result3 = (tab == moved);
BOOST_CHECK(result3);
}
{
value_type v1(42);
@@ -417,9 +193,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_exact, value_type, test_value_types)
value_type v2(54);
toml::find(v, "key") = v2;
BOOST_CHECK(v2 == toml::find(v, "key"));
const auto moved = toml::find(std::move(v), "key");
BOOST_CHECK(v2 == moved);
}
}
@@ -436,7 +209,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_integer_type, value_type, test_value_typ
BOOST_TEST(std::uint64_t(42) == toml::find<std::uint64_t>(v, "key"));
BOOST_TEST(std::int16_t(42) == toml::find<std::int16_t >(v, "key"));
BOOST_TEST(std::uint16_t(42) == toml::find<std::uint16_t>(v, "key"));
BOOST_TEST(std::uint16_t(42) == toml::find<std::uint16_t>(std::move(v), "key"));
}
}
@@ -444,11 +216,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_floating_type, value_type, test_value_ty
{
{
value_type v{{"key", 3.14}};
const double ref(3.14);
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(v, "key"));
BOOST_TEST( ref == toml::find<double >(v, "key"));
BOOST_TEST(static_cast<long double>(ref) == toml::find<long double>(v, "key"));
BOOST_TEST(static_cast<float >(ref) == toml::find<float >(std::move(v), "key"));
BOOST_TEST(static_cast<float >(3.14) == toml::find<float >(v, "key"));
BOOST_TEST(static_cast<double >(3.14) == toml::find<double >(v, "key"));
BOOST_TEST(static_cast<long double>(3.14) == toml::find<long double>(v, "key"));
}
}
@@ -466,13 +236,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_string_type, value_type, test_value_type
toml::find<std::string>(v, "key") += "bar";
BOOST_TEST("foobar" == toml::find<std::string>(v, "key"));
}
{
value_type v{{"key", toml::string("foo", toml::string_t::literal)}};
const auto moved = toml::find<std::string>(std::move(v), "key");
BOOST_TEST("foo" == moved);
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __cplusplus >= 201703L
{
value_type v{{"key", toml::string("foo", toml::string_t::basic)}};
BOOST_TEST("foo" == toml::find<std::string_view>(v, "key"));
@@ -509,14 +274,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array, value_type, test_value_types
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::find<std::array<int, 4>>(v, "key");
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
BOOST_TEST(static_cast<int>(42) == ary.at(0));
BOOST_TEST(static_cast<int>(54) == ary.at(1));
BOOST_TEST(static_cast<int>(69) == ary.at(2));
BOOST_TEST(static_cast<int>(72) == ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::find<std::tuple<int, short, unsigned, long>>(v, "key");
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
@@ -527,53 +292,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array, value_type, test_value_types
BOOST_TEST(2.71 == pr.second);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_move_toml_array, value_type, test_value_types)
{
value_type v1{{"key", {42, 54, 69, 72}}};
value_type v2{{"key", {42, 54, 69, 72}}};
value_type v3{{"key", {42, 54, 69, 72}}};
value_type v4{{"key", {42, 54, 69, 72}}};
value_type v5{{"key", {42, 54, 69, 72}}};
const std::vector<int> vec = toml::find<std::vector<int>>(std::move(v1), "key");
const std::list<short> lst = toml::find<std::list<short>>(std::move(v2), "key");
const std::deque<std::int64_t> deq = toml::find<std::deque<std::int64_t>>(std::move(v3), "key");
BOOST_TEST(42 == vec.at(0));
BOOST_TEST(54 == vec.at(1));
BOOST_TEST(69 == vec.at(2));
BOOST_TEST(72 == vec.at(3));
std::list<short>::const_iterator iter = lst.begin();
BOOST_TEST(static_cast<short>(42) == *(iter++));
BOOST_TEST(static_cast<short>(54) == *(iter++));
BOOST_TEST(static_cast<short>(69) == *(iter++));
BOOST_TEST(static_cast<short>(72) == *(iter++));
BOOST_TEST(static_cast<std::int64_t>(42) == deq.at(0));
BOOST_TEST(static_cast<std::int64_t>(54) == deq.at(1));
BOOST_TEST(static_cast<std::int64_t>(69) == deq.at(2));
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::find<std::array<int, 4>>(std::move(v4), "key");
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::find<std::tuple<int, short, unsigned, long>>(std::move(v5), "key");
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
value_type p{{"key", {3.14, 2.71}}};
std::pair<double, double> pr = toml::find<std::pair<double, double> >(std::move(p), "key");
BOOST_TEST(3.14 == pr.first);
BOOST_TEST(2.71 == pr.second);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array_of_array, value_type, test_value_types)
{
value_type v1{42, 54, 69, 72};
@@ -605,42 +323,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_array_of_array, value_type, test_va
BOOST_TEST(std::get<1>(t).at(2) == "baz");
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_move_toml_array_of_array, value_type, test_value_types)
{
value_type a1{42, 54, 69, 72};
value_type a2{"foo", "bar", "baz"};
value_type v1{{"key", {a1, a2}}};
value_type v2{{"key", {a1, a2}}};
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::find<std::pair<std::vector<int>, std::vector<std::string>>>(std::move(v1), "key");
BOOST_TEST(p.first.at(0) == 42);
BOOST_TEST(p.first.at(1) == 54);
BOOST_TEST(p.first.at(2) == 69);
BOOST_TEST(p.first.at(3) == 72);
BOOST_TEST(p.second.at(0) == "foo");
BOOST_TEST(p.second.at(1) == "bar");
BOOST_TEST(p.second.at(2) == "baz");
std::tuple<std::vector<int>, std::vector<std::string>> t =
toml::find<std::tuple<std::vector<int>, std::vector<std::string>>>(std::move(v2), "key");
BOOST_TEST(std::get<0>(t).at(0) == 42);
BOOST_TEST(std::get<0>(t).at(1) == 54);
BOOST_TEST(std::get<0>(t).at(2) == 69);
BOOST_TEST(std::get<0>(t).at(3) == 72);
BOOST_TEST(std::get<1>(t).at(0) == "foo");
BOOST_TEST(std::get<1>(t).at(1) == "bar");
BOOST_TEST(std::get<1>(t).at(2) == "baz");
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_table, value_type, test_value_types)
{
{
value_type v1{{"key", {
{"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}
}}};
@@ -649,22 +333,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_table, value_type, test_value_types
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
{
value_type v1{{"key", {
{"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}
}}};
const auto v = toml::find<std::map<std::string, int>>(std::move(v1), "key");
BOOST_TEST(v.at("key1") == 1);
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_date, value_type, test_value_types)
{
{
value_type v1{{"key", toml::local_date{2018, toml::month_t::Apr, 1}}};
const auto date = std::chrono::system_clock::to_time_t(
toml::find<std::chrono::system_clock::time_point>(v1, "key"));
@@ -679,44 +351,18 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_date, value_type, test_value_
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
{
value_type v1{{"key", toml::local_date{2018, toml::month_t::Apr, 1}}};
const auto date = std::chrono::system_clock::to_time_t(
toml::find<std::chrono::system_clock::time_point>(std::move(v1), "key"));
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_time, value_type, test_value_types)
{
{
value_type v1{{"key", toml::local_time{12, 30, 45}}};
const auto time = toml::find<std::chrono::seconds>(v1, "key");
BOOST_CHECK(time == std::chrono::hours(12) +
std::chrono::minutes(30) + std::chrono::seconds(45));
}
{
value_type v1{{"key", toml::local_time{12, 30, 45}}};
const auto time = toml::find<std::chrono::seconds>(std::move(v1), "key");
BOOST_CHECK(time == std::chrono::hours(12) +
std::chrono::minutes(30) + std::chrono::seconds(45));
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_datetime, value_type, test_value_types)
{
{
value_type v1{{"key", toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45})}};
@@ -733,25 +379,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_toml_local_datetime, value_type, test_va
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
{
value_type v1{{"key", toml::local_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 45})}};
const auto date = std::chrono::system_clock::to_time_t(
toml::find<std::chrono::system_clock::time_point>(std::move(v1), "key"));
std::tm t;
t.tm_year = 2018 - 1900;
t.tm_mon = 4 - 1;
t.tm_mday = 1;
t.tm_hour = 12;
t.tm_min = 30;
t.tm_sec = 45;
t.tm_isdst = -1;
const auto c = std::mktime(&t);
BOOST_TEST(c == date);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_offset_datetime, value_type, test_value_types)
@@ -801,27 +428,5 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_offset_datetime, value_type, test_va
BOOST_TEST(tm.tm_min == 30);
BOOST_TEST(tm.tm_sec == 0);
}
{
value_type v1{{"key", toml::offset_datetime(
toml::local_date{2018, toml::month_t::Apr, 1},
toml::local_time{12, 30, 0},
toml::time_offset{-8, 0})}};
// 2018-04-01T12:30:00-08:00
// == 2018-04-01T20:30:00Z
const auto date = toml::find<std::chrono::system_clock::time_point>(std::move(v1), "key");
const auto timet = std::chrono::system_clock::to_time_t(date);
// get time_t as gmtime (2018-04-01T03:30:00Z)
const auto tmp = std::gmtime(std::addressof(timet)); // XXX not threadsafe!
BOOST_CHECK(tmp);
const auto tm = *tmp;
BOOST_TEST(tm.tm_year + 1900 == 2018);
BOOST_TEST(tm.tm_mon + 1 == 4);
BOOST_TEST(tm.tm_mday == 1);
BOOST_TEST(tm.tm_hour == 20);
BOOST_TEST(tm.tm_min == 30);
BOOST_TEST(tm.tm_sec == 0);
}
}

350
tests/test_find_fuzzy.cpp Normal file
View File

@@ -0,0 +1,350 @@
#define BOOST_TEST_MODULE "test_find_fuzzy"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
BOOST_AUTO_TEST_CASE(test_levenstein_distance)
{
const toml::levenstein_matcher lev(1);
// distance == 0
{
const std::string s1("foobar");
const std::string s2 = s1;
BOOST_TEST(lev.distance(s1, s2) == 0);
}
{
const std::string s1("foobar");
const std::string s2("foobaz");
BOOST_TEST(lev.distance(s1, s2) == 1);
}
{
const std::string s1("foobar"); // insertion (+x)
const std::string s2("fooxbar");
BOOST_TEST(lev.distance(s1, s2) == 1);
}
{
const std::string s1("foobar");
const std::string s2("fooar"); // insertion(+b)
BOOST_TEST(lev.distance(s1, s2) == 1);
}
// distance > 1
{
const std::string s1("foobar");
const std::string s2("fooquux");
BOOST_TEST(lev.distance(s1, s2) == 4);
}
{
const std::string s1("foobar");
const std::string s2("fooqu");
BOOST_TEST(s1 != s2);
BOOST_TEST(lev.distance(s1, s2) == 3);
}
}
BOOST_AUTO_TEST_CASE(test_find_fuzzy)
{
{
toml::value v{
{"keu", "value"} // typo! key -> keu
};
BOOST_TEST(toml::find_fuzzy(v, "key") == toml::value("value"));
BOOST_CHECK_THROW(toml::find_fuzzy(v, "kiwi"), std::out_of_range);
static_assert(std::is_same<
toml::value&, decltype(toml::find_fuzzy(v, "key"))>::value, "");
toml::find_fuzzy(v, "key") = "foobar";
BOOST_TEST(toml::find(v, "keu") == toml::value("foobar"));
}
{
const toml::value v{
{"keu", "value"} // typo! key -> keu
};
BOOST_TEST(toml::find_fuzzy(v, "key") == toml::value("value"));
BOOST_CHECK_THROW(toml::find_fuzzy(v, "kiwi"), std::out_of_range);
static_assert(std::is_same<
toml::value const&, decltype(toml::find_fuzzy(v, "key"))>::value, "");
}
{
toml::value v{
{"keu", "value"} // typo! key -> keu
};
BOOST_TEST(toml::find_fuzzy(std::move(v), "key") == toml::value("value"));
static_assert(std::is_same<
toml::value&&, decltype(toml::find_fuzzy(std::move(v), "key"))>::value, "");
}
{
toml::value v{
{"keu", "value"} // typo! key -> keu
};
BOOST_CHECK_THROW(toml::find_fuzzy(std::move(v), "kiwi"), std::out_of_range);
static_assert(std::is_same<
toml::value&&, decltype(toml::find_fuzzy(std::move(v), "key"))>::value, "");
}
// find with conversion
{
toml::value v{
{"keu", 42} // typo! key -> keu
};
BOOST_TEST(toml::find_fuzzy<int>(v, "key") == 42);
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "kiwi"), std::out_of_range);
static_assert(std::is_same<int,
decltype(toml::find_fuzzy<int>(v, "key"))>::value, "");
}
{
const toml::value v{
{"keu", 42} // typo! key -> keu
};
BOOST_TEST(toml::find_fuzzy<int>(v, "key") == 42);
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "kiwi"), std::out_of_range);
static_assert(std::is_same<int,
decltype(toml::find_fuzzy<int>(v, "key"))>::value, "");
}
{
toml::value v{
{"keu", 42} // typo! key -> keu
};
BOOST_TEST(toml::find_fuzzy<int>(std::move(v), "key") == 42);
static_assert(std::is_same<int,
decltype(toml::find_fuzzy<int>(std::move(v), "key"))>::value, "");
}
{
toml::value v{
{"keu", 42} // typo! key -> keu
};
BOOST_CHECK_THROW(toml::find_fuzzy<int>(std::move(v), "kiwi"), std::out_of_range);
}
}
BOOST_AUTO_TEST_CASE(test_find_fuzzy_throw)
{
{
toml::value v{
{"keu", "value"}, // typo! key -> keu
{"ky", "value"} // typo! key -> ky
};
BOOST_CHECK_THROW(toml::find_fuzzy(v, "key"), std::out_of_range);
}
{
const toml::value v{
{"keu", "value"}, // typo! key -> keu
{"ky", "value"} // typo! key -> ky
};
BOOST_CHECK_THROW(toml::find_fuzzy(v, "key"), std::out_of_range);
}
{
toml::value v{
{"keu", "value"}, // typo! key -> keu
{"ky", "value"} // typo! key -> ky
};
BOOST_CHECK_THROW(toml::find_fuzzy(std::move(v), "key"), std::out_of_range);
}
{
toml::value v{
{"keu", 42}, // typo! key -> keu
{"ky", 42} // typo! key -> ky
};
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "key"), std::out_of_range);
}
{
const toml::value v{
{"keu", 42}, // typo! key -> keu
{"ky", 42} // typo! key -> ky
};
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "key"), std::out_of_range);
}
{
toml::value v{
{"keu", 42}, // typo! key -> keu
{"ky", 42} // typo! key -> ky
};
BOOST_CHECK_THROW(toml::find_fuzzy<int>(std::move(v), "key"), std::out_of_range);
}
}
BOOST_AUTO_TEST_CASE(test_find_throw_typo_aware_exception)
{
using namespace toml::literals::toml_literals;
const toml::levenstein_matcher lev(1);
{
toml::value v = u8R"(
keu = "value"
)"_toml;
BOOST_CHECK_THROW(toml::find(v, "key", lev), std::out_of_range);
try
{
const auto& ret = toml::find(v, "key", lev);
(void)ret; // suppress unused variable
}
catch(const std::out_of_range& oor)
{
// exception.what() should include the typo-ed key name
const std::string what(oor.what());
BOOST_TEST(what.find("keu") != std::string::npos);
// std::cout << what << std::endl;
}
static_assert(std::is_same<
toml::value&, decltype(toml::find(v, "key"))>::value, "");
}
{
const toml::value v = u8R"(
keu = "value"
)"_toml;
BOOST_CHECK_THROW(toml::find(v, "key", lev), std::out_of_range);
try
{
const auto& ret = toml::find(v, "key", lev);
(void)ret;
}
catch(const std::out_of_range& oor)
{
// exception.what() should include the typo-ed key name
const std::string what(oor.what());
BOOST_TEST(what.find("keu") != std::string::npos);
// std::cout << what << std::endl;
}
static_assert(std::is_same<
toml::value const&, decltype(toml::find(v, "key"))>::value, "");
}
{
toml::value v = u8R"(
keu = "value"
)"_toml;
bool thrown = false; // since it moves, we need to check both once
try
{
const auto& ret = toml::find(std::move(v), "key", lev);
(void)ret;
}
catch(const std::out_of_range& oor)
{
// exception.what() should include the typo-ed key name
const std::string what(oor.what());
BOOST_TEST(what.find("keu") != std::string::npos);
thrown = true;
// std::cout << what << std::endl;
}
BOOST_TEST(thrown);
static_assert(std::is_same<
toml::value&, decltype(toml::find(v, "key"))>::value, "");
}
}
BOOST_AUTO_TEST_CASE(test_find_throw_conversion_typo_aware_exception)
{
using namespace toml::literals::toml_literals;
const toml::levenstein_matcher lev(1);
{
toml::value v = u8R"(
keu = 42
)"_toml;
BOOST_CHECK_THROW(toml::find<int>(v, "key", lev), std::out_of_range);
try
{
const auto& ret = toml::find<int>(v, "key", lev);
(void)ret; // suppress unused variable
}
catch(const std::out_of_range& oor)
{
// exception.what() should include the typo-ed key name
const std::string what(oor.what());
BOOST_TEST(what.find("keu") != std::string::npos);
// std::cout << what << std::endl;
}
static_assert(std::is_same<int,
decltype(toml::find<int>(v, "key"))>::value, "");
}
{
const toml::value v = u8R"(
keu = 42
)"_toml;
BOOST_CHECK_THROW(toml::find<int>(v, "key", lev), std::out_of_range);
try
{
const auto& ret = toml::find<int>(v, "key", lev);
(void)ret;
}
catch(const std::out_of_range& oor)
{
// exception.what() should include the typo-ed key name
const std::string what(oor.what());
BOOST_TEST(what.find("keu") != std::string::npos);
// std::cout << what << std::endl;
}
static_assert(std::is_same<int,
decltype(toml::find<int>(v, "key"))>::value, "");
}
{
toml::value v = u8R"(
keu = 42
)"_toml;
bool thrown = false; // since it moves, we need to check both once
try
{
const auto& ret = toml::find<int>(std::move(v), "key", lev);
(void)ret;
}
catch(const std::out_of_range& oor)
{
// exception.what() should include the typo-ed key name
const std::string what(oor.what());
BOOST_TEST(what.find("keu") != std::string::npos);
thrown = true;
// std::cout << what << std::endl;
}
BOOST_TEST(thrown);
static_assert(std::is_same<int,
decltype(toml::find<int>(v, "key"))>::value, "");
}
}

View File

@@ -1,20 +1,23 @@
#define BOOST_TEST_MODULE "test_find_or"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <array>
#include <deque>
#include <list>
#include <map>
#include <tuple>
#include <unordered_map>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <list>
#include <deque>
#include <array>
#include <tuple>
#if __cplusplus >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::value,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
@@ -118,55 +121,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_exact, value_type, test_value_types)
}
#undef TOML11_TEST_FIND_OR_EXACT
#define TOML11_TEST_FIND_OR_MOVE(toml_type, init_expr, opt_expr) \
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt opt_expr ; \
value_type v{{"key", init}}; \
BOOST_TEST(init != opt); \
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));\
BOOST_TEST(init == moved); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_MOVE(boolean, ( true), (false))
TOML11_TEST_FIND_OR_MOVE(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_MOVE(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_MOVE(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_MOVE(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_MOVE(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_MOVE(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_MOVE(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt {6,7,8,9,10};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
}
#undef TOML11_TEST_FIND_OR_MOVE
#define TOML11_TEST_FIND_OR_MODIFY(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
@@ -350,20 +304,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_fallback, value_type, test_value_type
BOOST_AUTO_TEST_CASE(test_find_or_integer)
{
{
toml::value v{{"num", 42}};
toml::value v = toml::table{{"num", 42}};
BOOST_TEST(42u == toml::find_or(v, "num", 0u));
BOOST_TEST(0u == toml::find_or(v, "foo", 0u));
}
{
toml::value v{{"num", 42}};
const auto moved = toml::find_or(std::move(v), "num", 0u);
BOOST_TEST(42u == moved);
}
{
toml::value v{{"num", 42}};
const auto moved = toml::find_or(std::move(v), "foo", 0u);
BOOST_TEST(0u == moved);
}
}
BOOST_AUTO_TEST_CASE(test_find_or_floating)
@@ -372,17 +316,7 @@ BOOST_AUTO_TEST_CASE(test_find_or_floating)
toml::value v1{{"key", 42}};
toml::value v2{{"key", 3.14}};
BOOST_TEST(2.71f == toml::find_or(v1, "key", 2.71f));
const double ref(3.14);
BOOST_TEST(static_cast<float>(ref) == toml::find_or(v2, "key", 2.71f));
}
{
toml::value v1{{"key", 42}};
toml::value v2{{"key", 3.14}};
const auto moved1 = toml::find_or(std::move(v1), "key", 2.71f);
const auto moved2 = toml::find_or(std::move(v2), "key", 2.71f);
BOOST_TEST(2.71f == moved1);
const double ref(3.14);
BOOST_TEST(static_cast<float>(ref) == moved2);
BOOST_TEST(static_cast<float>(double(3.14)) == toml::find_or(v2, "key", 2.71f));
}
}
@@ -411,32 +345,6 @@ BOOST_AUTO_TEST_CASE(test_find_or_string)
s1 = "bazqux"; // restoring moved value
BOOST_TEST("bazqux" == toml::find_or(std::move(v2), "key", std::move(s1)));
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key", 42}};
std::string s1("bazqux");
const auto moved1 = toml::find_or(std::move(v1), "key", s1);
const auto moved2 = toml::find_or(std::move(v2), "key", s1);
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key", 42}};
std::string s1("bazqux");
std::string s2("bazqux");
const auto moved1 = toml::find_or(std::move(v1), "key", std::move(s1));
const auto moved2 = toml::find_or(std::move(v2), "key", std::move(s2));
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
// string literal
{
toml::value v1 = toml::table{{"key", "foobar"}};
@@ -449,28 +357,6 @@ BOOST_AUTO_TEST_CASE(test_find_or_string)
BOOST_TEST("foobar" == toml::find_or(v1, "key", lit));
BOOST_TEST("bazqux" == toml::find_or(v2, "key", lit));
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key",42}};
const auto moved1 = toml::find_or(std::move(v1), "key", "bazqux");
const auto moved2 = toml::find_or(std::move(v2), "key", "bazqux");
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
{
toml::value v1 = toml::table{{"key", "foobar"}};
toml::value v2 = toml::table{{"key",42}};
const char* lit = "bazqux";
const auto moved1 = toml::find_or(std::move(v1), "key", lit);
const auto moved2 = toml::find_or(std::move(v2), "key", lit);
BOOST_TEST("foobar" == moved1);
BOOST_TEST("bazqux" == moved2);
}
}
BOOST_AUTO_TEST_CASE(test_find_or_map)
@@ -491,7 +377,7 @@ BOOST_AUTO_TEST_CASE(test_find_or_map)
BOOST_TEST(key.at("key") == "value");
}
{
toml::value v1{
const toml::value v1{
{"key", {{"key", "value"}}}
};
@@ -504,35 +390,4 @@ BOOST_AUTO_TEST_CASE(test_find_or_map)
BOOST_TEST(key.size() == 1u);
BOOST_TEST(key.at("key") == "value");
}
{
toml::value v1{
{"key", {{"key", "value"}}}
};
toml::value v2(v1);
const auto key = toml::find_or(std::move(v1), "key", map_type{});
const auto key2 = toml::find_or(std::move(v2), "key2", map_type{});
BOOST_TEST(!key.empty());
BOOST_TEST(key2.empty());
BOOST_TEST(key.size() == 1u);
BOOST_TEST(key.at("key") == "value");
}
{
toml::value v1{
{"key", {{"key", "value"}}}
};
toml::value v2(v1);
const auto key = toml::find_or<map_type>(std::move(v1), "key", map_type{});
const auto key2 = toml::find_or<map_type>(std::move(v2), "key2", map_type{});
BOOST_TEST(!key.empty());
BOOST_TEST(key2.empty());
BOOST_TEST(key.size() == 1u);
BOOST_TEST(key.at("key") == "value");
}
}

View File

@@ -1,393 +0,0 @@
#include <toml.hpp>
#include "unit_test.hpp"
#include <array>
#include <deque>
#include <list>
#include <map>
#include <tuple>
#include <unordered_map>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
namespace test
{
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::vector<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::deque<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::list<T, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << i << ' ';}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Comp, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::map<Key, Value, Comp, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
template<typename charT, typename traits,
typename Key, typename Value, typename Hash, typename Eq, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const std::unordered_map<Key, Value, Hash, Eq, Alloc>& v)
{
os << "[ ";
for(const auto& i : v) {os << '{' << i.first << ", " << i.second << "} ";}
os << ']';
return os;
}
} // test
#define TOML11_TEST_FIND_OR_EXACT(toml_type, init_expr, opt_expr) \
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
const toml::toml_type opt opt_expr ; \
const value_type v{{"key1", value_type{{"key2", init}} }};\
BOOST_TEST(init != opt); \
BOOST_TEST(init == toml::find_or(v, "key1", "key2", opt));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_exact, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_EXACT(boolean, ( true), (false))
TOML11_TEST_FIND_OR_EXACT(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_EXACT(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_EXACT(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_EXACT(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_EXACT(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_EXACT(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_EXACT(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
const typename value_type::array_type init{1,2,3,4,5};
const typename value_type::array_type opt {6,7,8,9,10};
const value_type v{{"key", init}};
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::find_or(v, "key", opt));
}
{
const typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
const typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
const value_type v{{"key", init}};
BOOST_TEST(init != opt);
BOOST_TEST(init == toml::find_or(v, "key", opt));
}
}
#undef TOML11_TEST_FIND_OR_EXACT
#define TOML11_TEST_FIND_OR_MOVE(toml_type, init_expr, opt_expr) \
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt opt_expr ; \
value_type v{{"key1", value_type{{"key2", init}} }}; \
BOOST_TEST(init != opt); \
const auto moved = toml::find_or(std::move(v), "key1", "key2", std::move(opt));\
BOOST_TEST(init == moved); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_MOVE(boolean, ( true), (false))
TOML11_TEST_FIND_OR_MOVE(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_MOVE(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_MOVE(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_MOVE(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_MOVE(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_MOVE(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_MOVE(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt {6,7,8,9,10};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
value_type v{{"key", init}};
BOOST_TEST(init != opt);
const auto moved = toml::find_or(std::move(v), "key", std::move(opt));
BOOST_TEST(init == moved);
}
}
#undef TOML11_TEST_FIND_OR_MOVE
#define TOML11_TEST_FIND_OR_MODIFY(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt1 opt_expr ; \
toml::toml_type opt2 opt_expr ; \
value_type v{{"key1", value_type{{"key2", init}} }}; \
BOOST_TEST(init != opt1); \
toml::find_or(v, "key1", "key2", opt2) = opt1; \
BOOST_TEST(opt1 == toml::find<toml::toml_type>(v, "key1", "key2"));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_modify, value_type, test_value_types)
{
TOML11_TEST_FIND_OR_MODIFY(boolean, ( true), (false))
TOML11_TEST_FIND_OR_MODIFY(integer, ( 42), ( 54))
TOML11_TEST_FIND_OR_MODIFY(floating, ( 3.14), ( 2.71))
TOML11_TEST_FIND_OR_MODIFY(string, ("foo"), ("bar"))
TOML11_TEST_FIND_OR_MODIFY(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_FIND_OR_MODIFY(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_FIND_OR_MODIFY(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_FIND_OR_MODIFY(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt1{6,7,8,9,10};
typename value_type::array_type opt2{6,7,8,9,10};
BOOST_TEST(init != opt1);
value_type v{{"key", init}};
toml::find_or(v, "key", opt2) = opt1;
BOOST_TEST(opt1 == toml::find<typename value_type::array_type>(v, "key"));
}
{
typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt1{{"key1", 54}, {"key2", "bar"}};
typename value_type::table_type opt2{{"key1", 54}, {"key2", "bar"}};
value_type v{{"key", init}};
BOOST_TEST(init != opt1);
toml::find_or(v, "key", opt2) = opt1;
BOOST_TEST(opt1 == toml::find<typename value_type::table_type>(v, "key"));
}
}
#undef TOML11_TEST_FIND_OR_MODIFY
#define TOML11_TEST_FIND_OR_FALLBACK(init_type, opt_type) \
{ \
using namespace test; \
value_type v1{{"key1", value_type{{"key3", "foo"}}}}; \
BOOST_TEST(opt_type == toml::find_or(v1, "key1", "key2", opt_type));\
value_type v2{{"key1", "foo"}}; \
BOOST_TEST(opt_type == toml::find_or(v2, "key1", "key3", opt_type));\
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_fallback, value_type, test_value_types)
{
const toml::boolean boolean (true);
const toml::integer integer (42);
const toml::floating floating (3.14);
const toml::string string ("foo");
const toml::local_time local_time (12, 30, 45);
const toml::local_date local_date (2019, toml::month_t::Apr, 1);
const toml::local_datetime local_datetime (
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45));
const toml::offset_datetime offset_datetime(
toml::local_date(2019, toml::month_t::Apr, 1),
toml::local_time(12, 30, 45), toml::time_offset( 9, 0));
using array_type = typename value_type::array_type;
using table_type = typename value_type::table_type;
const array_type array{1, 2, 3, 4, 5};
const table_type table{{"key1", 42}, {"key2", "foo"}};
TOML11_TEST_FIND_OR_FALLBACK(boolean, integer );
TOML11_TEST_FIND_OR_FALLBACK(boolean, floating );
TOML11_TEST_FIND_OR_FALLBACK(boolean, string );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_time );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_date );
TOML11_TEST_FIND_OR_FALLBACK(boolean, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(boolean, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(boolean, array );
TOML11_TEST_FIND_OR_FALLBACK(boolean, table );
TOML11_TEST_FIND_OR_FALLBACK(integer, boolean );
TOML11_TEST_FIND_OR_FALLBACK(integer, floating );
TOML11_TEST_FIND_OR_FALLBACK(integer, string );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_time );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_date );
TOML11_TEST_FIND_OR_FALLBACK(integer, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(integer, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(integer, array );
TOML11_TEST_FIND_OR_FALLBACK(integer, table );
TOML11_TEST_FIND_OR_FALLBACK(floating, boolean );
TOML11_TEST_FIND_OR_FALLBACK(floating, integer );
TOML11_TEST_FIND_OR_FALLBACK(floating, string );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_time );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_date );
TOML11_TEST_FIND_OR_FALLBACK(floating, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(floating, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(floating, array );
TOML11_TEST_FIND_OR_FALLBACK(floating, table );
TOML11_TEST_FIND_OR_FALLBACK(string, boolean );
TOML11_TEST_FIND_OR_FALLBACK(string, integer );
TOML11_TEST_FIND_OR_FALLBACK(string, floating );
TOML11_TEST_FIND_OR_FALLBACK(string, local_time );
TOML11_TEST_FIND_OR_FALLBACK(string, local_date );
TOML11_TEST_FIND_OR_FALLBACK(string, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(string, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(string, array );
TOML11_TEST_FIND_OR_FALLBACK(string, table );
TOML11_TEST_FIND_OR_FALLBACK(local_time, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_time, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_time, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_time, string );
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_date );
TOML11_TEST_FIND_OR_FALLBACK(local_time, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(local_time, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_time, array );
TOML11_TEST_FIND_OR_FALLBACK(local_time, table );
TOML11_TEST_FIND_OR_FALLBACK(local_date, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_date, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_date, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_date, string );
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_time );
TOML11_TEST_FIND_OR_FALLBACK(local_date, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(local_date, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_date, array );
TOML11_TEST_FIND_OR_FALLBACK(local_date, table );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, boolean );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, integer );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, floating );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, string );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_time );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, local_date );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, array );
TOML11_TEST_FIND_OR_FALLBACK(local_datetime, table );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, boolean );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, integer );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, floating );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, string );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_time );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_date );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, array );
TOML11_TEST_FIND_OR_FALLBACK(offset_datetime, table );
TOML11_TEST_FIND_OR_FALLBACK(array, boolean );
TOML11_TEST_FIND_OR_FALLBACK(array, integer );
TOML11_TEST_FIND_OR_FALLBACK(array, floating );
TOML11_TEST_FIND_OR_FALLBACK(array, string );
TOML11_TEST_FIND_OR_FALLBACK(array, local_time );
TOML11_TEST_FIND_OR_FALLBACK(array, local_date );
TOML11_TEST_FIND_OR_FALLBACK(array, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(array, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(array, table );
TOML11_TEST_FIND_OR_FALLBACK(table, boolean );
TOML11_TEST_FIND_OR_FALLBACK(table, integer );
TOML11_TEST_FIND_OR_FALLBACK(table, floating );
TOML11_TEST_FIND_OR_FALLBACK(table, string );
TOML11_TEST_FIND_OR_FALLBACK(table, local_time );
TOML11_TEST_FIND_OR_FALLBACK(table, local_date );
TOML11_TEST_FIND_OR_FALLBACK(table, local_datetime );
TOML11_TEST_FIND_OR_FALLBACK(table, offset_datetime);
TOML11_TEST_FIND_OR_FALLBACK(table, array );
}
#undef TOML11_TEST_FIND_OR_FALLBACK
struct move_only_type
{
explicit move_only_type(const std::string& n): name_(n) {}
void from_toml(const toml::value& v)
{
this->name_ = toml::find<std::string>(v, "name");
return;
}
move_only_type(): name_("default"){}
~move_only_type() = default;
move_only_type(move_only_type&&) = default;
move_only_type& operator=(move_only_type&&) = default;
move_only_type(const move_only_type&) = delete;
move_only_type& operator=(const move_only_type&) = delete;
bool operator==(const move_only_type& other) const noexcept {return this->name_ == other.name_;}
bool operator!=(const move_only_type& other) const noexcept {return this->name_ != other.name_;}
bool operator< (const move_only_type& other) const noexcept {return this->name_ < other.name_;}
bool operator<=(const move_only_type& other) const noexcept {return this->name_ <= other.name_;}
bool operator> (const move_only_type& other) const noexcept {return this->name_ > other.name_;}
bool operator>=(const move_only_type& other) const noexcept {return this->name_ >= other.name_;}
std::string name_;
};
std::ostream& operator<<(std::ostream& os, const move_only_type& mot)
{
os << mot.name_;
return os;
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_find_or_move_only, value_type, test_value_types)
{
const move_only_type ref("reference");
move_only_type opt("optional");
{
const value_type v{{"key1", value_type{{"key2", value_type{{"name", "reference"}} }} }};
BOOST_TEST(ref == toml::find_or(v, "key1", "key2", std::move(opt)));
}
}

View File

@@ -1,7 +1,11 @@
#define BOOST_TEST_MODULE "test_format_error"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <iostream>
// to check it successfully compiles. it does not check the formatted string.

View File

@@ -1,20 +1,23 @@
#define BOOST_TEST_MODULE "test_get"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <array>
#include <deque>
#include <list>
#include <map>
#include <tuple>
#include <unordered_map>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <list>
#include <deque>
#include <array>
#include <tuple>
#if __cplusplus >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::value,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
@@ -28,9 +31,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::boolean>(v) = false;
BOOST_TEST(false == toml::get<toml::boolean>(v));
toml::boolean x = toml::get<toml::boolean>(std::move(v));
BOOST_TEST(false == x);
}
{
value_type v(42);
@@ -38,9 +38,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::integer>(v) = 54;
BOOST_TEST(toml::integer(54) == toml::get<toml::integer>(v));
toml::integer x = toml::get<toml::integer>(std::move(v));
BOOST_TEST(toml::integer(54) == x);
}
{
value_type v(3.14);
@@ -48,9 +45,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::floating>(v) = 2.71;
BOOST_TEST(toml::floating(2.71) == toml::get<toml::floating>(v));
toml::floating x = toml::get<toml::floating>(std::move(v));
BOOST_TEST(toml::floating(2.71) == x);
}
{
value_type v("foo");
@@ -60,9 +54,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::string>(v).str += "bar";
BOOST_TEST(toml::string("foobar", toml::string_t::basic) ==
toml::get<toml::string>(v));
toml::string x = toml::get<toml::string>(std::move(v));
BOOST_TEST(toml::string("foobar") == x);
}
{
value_type v("foo", toml::string_t::literal);
@@ -72,9 +63,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::string>(v).str += "bar";
BOOST_TEST(toml::string("foobar", toml::string_t::literal) ==
toml::get<toml::string>(v));
toml::string x = toml::get<toml::string>(std::move(v));
BOOST_TEST(toml::string("foobar", toml::string_t::literal) == x);
}
{
toml::local_date d(2018, toml::month_t::Apr, 22);
@@ -84,9 +72,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::local_date>(v).year = 2017;
d.year = 2017;
BOOST_TEST(d == toml::get<toml::local_date>(v));
toml::local_date x = toml::get<toml::local_date>(std::move(v));
BOOST_TEST(d == x);
}
{
toml::local_time t(12, 30, 45);
@@ -96,9 +81,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::local_time>(v).hour = 9;
t.hour = 9;
BOOST_TEST(t == toml::get<toml::local_time>(v));
toml::local_time x = toml::get<toml::local_time>(std::move(v));
BOOST_TEST(t == x);
}
{
toml::local_datetime dt(toml::local_date(2018, toml::month_t::Apr, 22),
@@ -109,9 +91,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::local_datetime>(v).date.year = 2017;
dt.date.year = 2017;
BOOST_TEST(dt == toml::get<toml::local_datetime>(v));
toml::local_datetime x = toml::get<toml::local_datetime>(std::move(v));
BOOST_TEST(dt == x);
}
{
toml::offset_datetime dt(toml::local_datetime(
@@ -123,9 +102,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<toml::offset_datetime>(v).date.year = 2017;
dt.date.year = 2017;
BOOST_TEST(dt == toml::get<toml::offset_datetime>(v));
toml::offset_datetime x = toml::get<toml::offset_datetime>(std::move(v));
BOOST_TEST(dt == x);
}
{
using array_type = typename value_type::array_type;
@@ -138,9 +114,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<array_type>(v).push_back(value_type(123));
vec.push_back(value_type(123));
BOOST_TEST(vec == toml::get<array_type>(v));
array_type x = toml::get<array_type>(std::move(v));
BOOST_TEST(vec == x);
}
{
using table_type = typename value_type::table_type;
@@ -153,9 +126,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
toml::get<table_type>(v)["key3"] = value_type(123);
tab["key3"] = value_type(123);
BOOST_TEST(tab == toml::get<table_type>(v));
table_type x = toml::get<table_type>(std::move(v));
BOOST_TEST(tab == x);
}
{
value_type v1(42);
@@ -164,9 +134,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_exact, value_type, test_value_types)
value_type v2(54);
toml::get<value_type>(v1) = v2;
BOOST_TEST(v2 == toml::get<value_type>(v1));
value_type x = toml::get<value_type>(std::move(v1));
BOOST_TEST(v2 == x);
}
}
@@ -183,8 +150,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_integer_type, value_type, test_value_type
BOOST_TEST(std::uint64_t(42) == toml::get<std::uint64_t>(v));
BOOST_TEST(std::int16_t(42) == toml::get<std::int16_t >(v));
BOOST_TEST(std::uint16_t(42) == toml::get<std::uint16_t>(v));
BOOST_TEST(std::uint16_t(42) == toml::get<std::uint16_t>(std::move(v)));
}
}
@@ -192,11 +157,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_floating_type, value_type, test_value_typ
{
{
value_type v(3.14);
const double ref(3.14);
BOOST_TEST(static_cast<float >(ref) == toml::get<float >(v));
BOOST_TEST( ref == toml::get<double >(v));
BOOST_TEST(static_cast<long double>(ref) == toml::get<long double>(v));
BOOST_TEST(static_cast<float >(ref) == toml::get<float>(std::move(v)));
BOOST_TEST(static_cast<float >(3.14) == toml::get<float >(v));
BOOST_TEST(static_cast<double >(3.14) == toml::get<double >(v));
BOOST_TEST(static_cast<long double>(3.14) == toml::get<long double>(v));
}
}
@@ -207,21 +170,15 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_string_type, value_type, test_value_types
BOOST_TEST("foo" == toml::get<std::string>(v));
toml::get<std::string>(v) += "bar";
BOOST_TEST("foobar" == toml::get<std::string>(v));
const auto x = toml::get<std::string>(std::move(v));
BOOST_TEST("foobar" == x);
}
{
value_type v("foo", toml::string_t::literal);
BOOST_TEST("foo" == toml::get<std::string>(v));
toml::get<std::string>(v) += "bar";
BOOST_TEST("foobar" == toml::get<std::string>(v));
const auto x = toml::get<std::string>(std::move(v));
BOOST_TEST("foobar" == x);
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __cplusplus >= 201703L
{
value_type v("foo", toml::string_t::basic);
BOOST_TEST("foo" == toml::get<std::string_view>(v));
@@ -235,7 +192,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_string_type, value_type, test_value_types
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
{
{
const value_type v{42, 54, 69, 72};
const std::vector<int> vec = toml::get<std::vector<int>>(v);
@@ -259,14 +215,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
BOOST_TEST(static_cast<std::int64_t>(72) == deq.at(3));
std::array<int, 4> ary = toml::get<std::array<int, 4>>(v);
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
BOOST_TEST(static_cast<int>(42) == ary.at(0));
BOOST_TEST(static_cast<int>(54) == ary.at(1));
BOOST_TEST(static_cast<int>(69) == ary.at(2));
BOOST_TEST(static_cast<int>(72) == ary.at(3));
std::tuple<int, short, unsigned, long> tpl =
toml::get<std::tuple<int, short, unsigned, long>>(v);
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<int >(42) == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
@@ -275,55 +231,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array, value_type, test_value_types)
std::pair<double, double> pr = toml::get<std::pair<double, double> >(p);
BOOST_TEST(3.14 == pr.first);
BOOST_TEST(2.71 == pr.second);
}
{
value_type v{42, 54, 69, 72};
const std::vector<int> vec = toml::get<std::vector<int>>(std::move(v));
BOOST_TEST(42 == vec.at(0));
BOOST_TEST(54 == vec.at(1));
BOOST_TEST(69 == vec.at(2));
BOOST_TEST(72 == vec.at(3));
}
{
value_type v{42, 54, 69, 72};
const std::deque<int> deq = toml::get<std::deque<int>>(std::move(v));
BOOST_TEST(42 == deq.at(0));
BOOST_TEST(54 == deq.at(1));
BOOST_TEST(69 == deq.at(2));
BOOST_TEST(72 == deq.at(3));
}
{
value_type v{42, 54, 69, 72};
const std::list<int> lst = toml::get<std::list<int>>(std::move(v));
std::list<int>::const_iterator iter = lst.begin();
BOOST_TEST(42 == *(iter++));
BOOST_TEST(54 == *(iter++));
BOOST_TEST(69 == *(iter++));
BOOST_TEST(72 == *(iter++));
}
{
value_type v{42, 54, 69, 72};
std::array<int, 4> ary = toml::get<std::array<int, 4>>(std::move(v));
BOOST_TEST(42 == ary.at(0));
BOOST_TEST(54 == ary.at(1));
BOOST_TEST(69 == ary.at(2));
BOOST_TEST(72 == ary.at(3));
}
{
value_type v{42, 54, 69, 72};
std::tuple<int, short, unsigned, long> tpl =
toml::get<std::tuple<int, short, unsigned, long>>(std::move(v));
BOOST_TEST( 42 == std::get<0>(tpl));
BOOST_TEST(static_cast<short >(54) == std::get<1>(tpl));
BOOST_TEST(static_cast<unsigned>(69) == std::get<2>(tpl));
BOOST_TEST(static_cast<long >(72) == std::get<3>(tpl));
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array_of_array, value_type, test_value_types)
{
{
const value_type v1{42, 54, 69, 72};
const value_type v2{"foo", "bar", "baz"};
const value_type v{v1, v2};
@@ -331,13 +242,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array_of_array, value_type, test_val
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::get<std::pair<std::vector<int>, std::vector<std::string>>>(v);
BOOST_TEST(p.first.size() == 4u);
BOOST_TEST(p.first.at(0) == 42);
BOOST_TEST(p.first.at(1) == 54);
BOOST_TEST(p.first.at(2) == 69);
BOOST_TEST(p.first.at(3) == 72);
BOOST_TEST(p.second.size() == 3u);
BOOST_TEST(p.second.at(0) == "foo");
BOOST_TEST(p.second.at(1) == "bar");
BOOST_TEST(p.second.at(2) == "baz");
@@ -353,31 +262,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_array_of_array, value_type, test_val
BOOST_TEST(std::get<1>(t).at(0) == "foo");
BOOST_TEST(std::get<1>(t).at(1) == "bar");
BOOST_TEST(std::get<1>(t).at(2) == "baz");
}
{
const value_type v1{42, 54, 69, 72};
const value_type v2{"foo", "bar", "baz"};
value_type v{v1, v2};
std::pair<std::vector<int>, std::vector<std::string>> p =
toml::get<std::pair<std::vector<int>, std::vector<std::string>>>(std::move(v));
BOOST_TEST(p.first.size() == 4u);
BOOST_TEST(p.first.at(0) == 42);
BOOST_TEST(p.first.at(1) == 54);
BOOST_TEST(p.first.at(2) == 69);
BOOST_TEST(p.first.at(3) == 72);
BOOST_TEST(p.second.size() == 3u);
BOOST_TEST(p.second.at(0) == "foo");
BOOST_TEST(p.second.at(1) == "bar");
BOOST_TEST(p.second.at(2) == "baz");
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_table, value_type, test_value_types)
{
{
const value_type v1{
{"key1", 1},
{"key2", 2},
@@ -390,21 +278,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_table, value_type, test_value_types)
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
{
value_type v1{
{"key1", 1},
{"key2", 2},
{"key3", 3},
{"key4", 4}
};
const auto v = toml::get<std::map<std::string, int>>(std::move(v1));
BOOST_TEST(v.at("key1") == 1);
BOOST_TEST(v.at("key2") == 2);
BOOST_TEST(v.at("key3") == 3);
BOOST_TEST(v.at("key4") == 4);
}
}
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_local_date, value_type, test_value_types)
@@ -503,3 +376,4 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_toml_offset_datetime, value_type, test_va
BOOST_TEST(tm.tm_sec == 0);
}
}

View File

@@ -1,20 +1,23 @@
#define BOOST_TEST_MODULE "test_get_or"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <array>
#include <deque>
#include <list>
#include <map>
#include <tuple>
#include <unordered_map>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <list>
#include <deque>
#include <array>
#include <tuple>
#if __cplusplus >= 201703L
#include <string_view>
#endif
using test_value_types = std::tuple<
toml::basic_value<toml::discard_comments>,
toml::value,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
@@ -22,11 +25,6 @@ using test_value_types = std::tuple<
namespace test
{
// to compare result values in BOOST_TEST().
//
// BOOST_TEST outputs the expected and actual values. Thus it includes the
// output stream operator inside. To compile it, we need operator<<s for
// containers to compare.
template<typename charT, typename traits, typename T, typename Alloc>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const std::vector<T, Alloc>& v)
@@ -123,55 +121,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_or_exact, value_type, test_value_types)
}
#undef TOML11_TEST_GET_OR_EXACT
#define TOML11_TEST_GET_OR_MOVE_EXACT(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
const toml::toml_type init init_expr ; \
toml::toml_type opt opt_expr ; \
value_type v(init); \
BOOST_TEST(init != opt); \
const auto opt_ = toml::get_or(std::move(v), std::move(opt));\
BOOST_TEST(init == opt_); \
} \
/**/
BOOST_AUTO_TEST_CASE_TEMPLATE(test_get_or_move, value_type, test_value_types)
{
TOML11_TEST_GET_OR_MOVE_EXACT(boolean, ( true), (false))
TOML11_TEST_GET_OR_MOVE_EXACT(integer, ( 42), ( 54))
TOML11_TEST_GET_OR_MOVE_EXACT(floating, ( 3.14), ( 2.71))
TOML11_TEST_GET_OR_MOVE_EXACT(string, ("foo"), ("bar"))
TOML11_TEST_GET_OR_MOVE_EXACT(local_time, (12, 30, 45), (6, 0, 30))
TOML11_TEST_GET_OR_MOVE_EXACT(local_date, (2019, toml::month_t::Apr, 1),
(1999, toml::month_t::Jan, 2))
TOML11_TEST_GET_OR_MOVE_EXACT(local_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30))
)
TOML11_TEST_GET_OR_MOVE_EXACT(offset_datetime,
(toml::local_date(2019, toml::month_t::Apr, 1), toml::local_time(12, 30, 45), toml::time_offset( 9, 0)),
(toml::local_date(1999, toml::month_t::Jan, 2), toml::local_time( 6, 0, 30), toml::time_offset(-3, 0))
)
{
const typename value_type::array_type init{1,2,3,4,5};
typename value_type::array_type opt {6,7,8,9,10};
value_type v(init);
BOOST_TEST(init != opt);
const auto opt_ = toml::get_or(std::move(v), std::move(opt));
BOOST_TEST(init == opt_);
}
{
const typename value_type::table_type init{{"key1", 42}, {"key2", "foo"}};
typename value_type::table_type opt {{"key1", 54}, {"key2", "bar"}};
value_type v(init);
BOOST_TEST(init != opt);
const auto opt_ = toml::get_or(std::move(v), std::move(opt));
BOOST_TEST(init == opt_);
}
}
#undef TOML11_TEST_GET_OR_MOVE_EXACT
#define TOML11_TEST_GET_OR_MODIFY(toml_type, init_expr, opt_expr)\
{ \
using namespace test; \
@@ -360,13 +309,6 @@ BOOST_AUTO_TEST_CASE(test_get_or_integer)
BOOST_TEST(42u == toml::get_or(v1, 0u));
BOOST_TEST(0u == toml::get_or(v2, 0u));
}
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_TEST(42u == toml::get_or(std::move(v1), 0u));
BOOST_TEST(0u == toml::get_or(std::move(v2), 0u));
}
}
BOOST_AUTO_TEST_CASE(test_get_or_floating)
@@ -377,12 +319,6 @@ BOOST_AUTO_TEST_CASE(test_get_or_floating)
BOOST_TEST(2.71f == toml::get_or(v1, 2.71f));
BOOST_TEST(static_cast<float>(v2.as_floating()) == toml::get_or(v2, 2.71f));
}
{
toml::value v1(42);
toml::value v2(3.14);
BOOST_TEST(2.71f == toml::get_or(std::move(v1), 2.71f));
BOOST_TEST(static_cast<float>(3.14) == toml::get_or(std::move(v2), 2.71f));
}
}
BOOST_AUTO_TEST_CASE(test_get_or_string)
@@ -409,16 +345,7 @@ BOOST_AUTO_TEST_CASE(test_get_or_string)
BOOST_TEST("foobar" == toml::get_or(v1, std::move(s1)));
BOOST_TEST("bazqux" == toml::get_or(v2, std::move(s1)));
}
{
toml::value v1("foobar");
toml::value v2(42);
std::string s1("bazqux");
const std::string s2("bazqux");
BOOST_TEST("foobar" == toml::get_or(std::move(v1), s1));
BOOST_TEST("bazqux" == toml::get_or(std::move(v2), s1));
}
{
toml::value v1("foobar");
toml::value v2(42);
@@ -430,20 +357,4 @@ BOOST_AUTO_TEST_CASE(test_get_or_string)
BOOST_TEST("foobar" == toml::get_or(v1, lit));
BOOST_TEST("bazqux" == toml::get_or(v2, lit));
}
{
toml::value v1("foobar");
toml::value v2(42);
BOOST_TEST("foobar" == toml::get_or(std::move(v1), "bazqux"));
BOOST_TEST("bazqux" == toml::get_or(std::move(v2), "bazqux"));
}
{
toml::value v1("foobar");
toml::value v2(42);
const char* lit = "bazqux";
BOOST_TEST("foobar" == toml::get_or(v1, lit));
BOOST_TEST("bazqux" == toml::get_or(v2, lit));
}
}

View File

@@ -8,7 +8,7 @@
do { \
const std::string token (tkn); \
const std::string expected(expct); \
toml::detail::location loc("test", token); \
toml::detail::location<std::string> loc("test", token); \
const auto result = lxr::invoke(loc); \
BOOST_TEST(result.is_ok()); \
if(result.is_ok()){ \
@@ -28,7 +28,7 @@ do { \
#define TOML11_TEST_LEX_REJECT(lxr, tkn) \
do { \
const std::string token (tkn); \
toml::detail::location loc("test", token); \
toml::detail::location<std::string> loc("test", token); \
const auto result = lxr::invoke(loc); \
BOOST_TEST(result.is_err()); \
const bool loc_same = (loc.begin() == loc.iter()); \

View File

@@ -1,6 +1,6 @@
#define BOOST_TEST_MODULE "test_lex_boolean"
#include <boost/test/unit_test.hpp>
#include <toml/lexer.hpp>
#include "unit_test.hpp"
#include "test_lex_aux.hpp"
using namespace toml;

View File

@@ -1,6 +1,6 @@
#define BOOST_TEST_MODULE "test_lex_datetime"
#include <boost/test/unit_test.hpp>
#include <toml/lexer.hpp>
#include "unit_test.hpp"
#include "test_lex_aux.hpp"
using namespace toml;

View File

@@ -1,9 +1,8 @@
#define BOOST_TEST_MODULE "test_lex_floating"
#include <boost/test/unit_test.hpp>
#include <toml/lexer.hpp>
#include "unit_test.hpp"
#include "test_lex_aux.hpp"
#include <limits>
#include "test_lex_aux.hpp"
using namespace toml;
using namespace detail;
@@ -52,18 +51,10 @@ BOOST_AUTO_TEST_CASE(test_exponential_valid)
TOML11_TEST_LEX_ACCEPT(lex_float, "123E-10", "123E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-10", "1_2_3E-10");
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-1_0", "1_2_3E-1_0");
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-01", "1_2_3E-01");
TOML11_TEST_LEX_ACCEPT(lex_float, "1_2_3E-0_1", "1_2_3E-0_1");
#endif
}
BOOST_AUTO_TEST_CASE(test_exponential_invalid)
{
// accept partially
TOML11_TEST_LEX_ACCEPT(lex_float, "1e1E0", "1e1");
TOML11_TEST_LEX_ACCEPT(lex_float, "1E1e0", "1E1");
}
@@ -73,26 +64,12 @@ BOOST_AUTO_TEST_CASE(test_both_valid)
TOML11_TEST_LEX_ACCEPT(lex_float, "6.02e23", "6.02e23");
TOML11_TEST_LEX_ACCEPT(lex_float, "6.02e+23", "6.02e+23");
TOML11_TEST_LEX_ACCEPT(lex_float, "1.112_650_06e-17", "1.112_650_06e-17");
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_LEX_ACCEPT(lex_float, "1.0e-07", "1.0e-07");
#endif
}
BOOST_AUTO_TEST_CASE(test_both_invalid)
{
TOML11_TEST_LEX_REJECT(lex_float, "01e1.0");
// accept partially
TOML11_TEST_LEX_ACCEPT(lex_float, "1e1.0", "1e1");
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_LEX_ACCEPT(lex_float, "1.0e_01", "1.0");
TOML11_TEST_LEX_ACCEPT(lex_float, "1.0e0__1", "1.0e0");
#endif
TOML11_TEST_LEX_REJECT(lex_float, "01e1.0");
}
BOOST_AUTO_TEST_CASE(test_special_floating_point)

View File

@@ -1,6 +1,6 @@
#define BOOST_TEST_MODULE "test_lex_integer"
#include <boost/test/unit_test.hpp>
#include <toml/lexer.hpp>
#include "unit_test.hpp"
#include "test_lex_aux.hpp"
using namespace toml;

View File

@@ -1,6 +1,6 @@
#define BOOST_TEST_MODULE "lex_key_comment_test"
#include <boost/test/unit_test.hpp>
#include <toml/lexer.hpp>
#include "unit_test.hpp"
#include "test_lex_aux.hpp"
using namespace toml;
@@ -18,11 +18,12 @@ BOOST_AUTO_TEST_CASE(test_quoted_key)
{
TOML11_TEST_LEX_ACCEPT(lex_key, "\"127.0.0.1\"", "\"127.0.0.1\"");
TOML11_TEST_LEX_ACCEPT(lex_key, "\"character encoding\"", "\"character encoding\"");
// UTF-8 codepoint of characters that looks like "key" written upside down
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
TOML11_TEST_LEX_ACCEPT(lex_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"",
"\"\xCA\x8E\xC7\x9D\xCA\x9E\"");
#else
TOML11_TEST_LEX_ACCEPT(lex_key, u8"\"ʎǝʞ\"", u8"\"ʎǝʞ\"");
#endif
TOML11_TEST_LEX_ACCEPT(lex_key, "'key2'", "'key2'");
TOML11_TEST_LEX_ACCEPT(lex_key, "'quoted \"value\"'", "'quoted \"value\"'");
}

View File

@@ -1,6 +1,6 @@
#define BOOST_TEST_MODULE "test_lex_string"
#include <boost/test/unit_test.hpp>
#include <toml/lexer.hpp>
#include "unit_test.hpp"
#include "test_lex_aux.hpp"
using namespace toml;
@@ -31,9 +31,15 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
"\"192.168.1.1\"",
"\"192.168.1.1\"");
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"", // UTF-8 string (means "China" in
"\"\xE4\xB8\xAD\xE5\x9B\xBD\""); // Chinese characters)
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"",
"\"\xE4\xB8\xAD\xE5\x9B\xBD\"");
#else
TOML11_TEST_LEX_ACCEPT(lex_string,
u8"\"中国\"",
u8"\"中国\"");
#endif
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"You'll hate me after this - #\"",
@@ -51,22 +57,6 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"");
TOML11_TEST_LEX_ACCEPT(lex_string,
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"");
}
BOOST_AUTO_TEST_CASE(test_literal_string)
@@ -93,16 +83,4 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
TOML11_TEST_LEX_ACCEPT(lex_string,
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''");
TOML11_TEST_LEX_ACCEPT(lex_string,
"''''That's still pointless', she said.'''",
"''''That's still pointless', she said.'''");
TOML11_TEST_LEX_ACCEPT(lex_string,
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''");
TOML11_TEST_LEX_ACCEPT(lex_string,
"''''This,' she said, 'is just a pointless statement.''''",
"''''This,' she said, 'is just a pointless statement.''''");
}

View File

@@ -1,7 +1,11 @@
#define BOOST_TEST_MODULE "test_literals"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <map>
BOOST_AUTO_TEST_CASE(test_file_as_literal)
@@ -10,7 +14,7 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
{
const toml::value r{{"a", 42}, {"b", "baz"}};
const toml::value v = R"(
const toml::value v = u8R"(
a = 42
b = "baz"
)"_toml;
@@ -22,7 +26,7 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
{"c", 3.14},
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = R"(
const toml::value v = u8R"(
c = 3.14
[table]
a = 42
@@ -35,7 +39,7 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
const toml::value r{
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = R"(
const toml::value v = u8R"(
[table]
a = 42
b = "baz"
@@ -47,7 +51,7 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
const toml::value r{
{"array_of_tables", toml::array{toml::table{}}}
};
const toml::value v = R"(
const toml::value v = u8R"(
[[array_of_tables]]
)"_toml;
@@ -59,170 +63,6 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
{
using namespace toml::literals::toml_literals;
{
const toml::value v1 = "true"_toml;
const toml::value v2 = "false"_toml;
BOOST_TEST(v1.is_boolean());
BOOST_TEST(v2.is_boolean());
BOOST_TEST(toml::get<bool>(v1));
BOOST_TEST(!toml::get<bool>(v2));
}
{
const toml::value v1 = "123_456"_toml;
const toml::value v2 = "0b0010"_toml;
const toml::value v3 = "0xDEADBEEF"_toml;
BOOST_TEST(v1.is_integer());
BOOST_TEST(v2.is_integer());
BOOST_TEST(v3.is_integer());
BOOST_TEST(toml::get<toml::integer>(v1) == 123456);
BOOST_TEST(toml::get<toml::integer>(v2) == 2);
BOOST_TEST(toml::get<toml::integer>(v3) == 0xDEADBEEF);
}
{
const toml::value v1 = "3.1415"_toml;
const toml::value v2 = "6.02e+23"_toml;
BOOST_TEST(v1.is_floating());
BOOST_TEST(v2.is_floating());
BOOST_TEST(toml::get<double>(v1) == 3.1415, boost::test_tools::tolerance(0.00001));
BOOST_TEST(toml::get<double>(v2) == 6.02e23, boost::test_tools::tolerance(0.0001));
}
{
const toml::value v1 = R"("foo")"_toml;
const toml::value v2 = R"('foo')"_toml;
const toml::value v3 = R"("""foo""")"_toml;
const toml::value v4 = R"('''foo''')"_toml;
BOOST_TEST(v1.is_string());
BOOST_TEST(v2.is_string());
BOOST_TEST(v3.is_string());
BOOST_TEST(v4.is_string());
BOOST_TEST(toml::get<std::string>(v1) == "foo");
BOOST_TEST(toml::get<std::string>(v2) == "foo");
BOOST_TEST(toml::get<std::string>(v3) == "foo");
BOOST_TEST(toml::get<std::string>(v4) == "foo");
}
{
{
const toml::value v1 = R"([1,2,3])"_toml;
BOOST_TEST(v1.is_array());
const bool result = (toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3});
BOOST_TEST(result);
}
{
const toml::value v2 = R"([1,])"_toml;
BOOST_TEST(v2.is_array());
const bool result = (toml::get<std::vector<int>>(v2) == std::vector<int>{1});
BOOST_TEST(result);
}
{
const toml::value v3 = R"([[1,]])"_toml;
BOOST_TEST(v3.is_array());
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v3).front()) == std::vector<int>{1});
BOOST_TEST(result);
}
{
const toml::value v4 = R"([[1],])"_toml;
BOOST_TEST(v4.is_array());
const bool result = (toml::get<std::vector<int>>(toml::get<toml::array>(v4).front()) == std::vector<int>{1});
BOOST_TEST(result);
}
}
{
const toml::value v1 = R"({a = 42})"_toml;
BOOST_TEST(v1.is_table());
const bool result = toml::get<std::map<std::string,int>>(v1) ==
std::map<std::string,int>{{"a", 42}};
BOOST_TEST(result);
}
{
const toml::value v1 = "1979-05-27"_toml;
BOOST_TEST(v1.is_local_date());
BOOST_TEST(toml::get<toml::local_date>(v1) ==
toml::local_date(1979, toml::month_t::May, 27));
}
{
const toml::value v1 = "12:00:00"_toml;
BOOST_TEST(v1.is_local_time());
const bool result = toml::get<std::chrono::hours>(v1) == std::chrono::hours(12);
BOOST_TEST(result);
}
{
const toml::value v1 = "1979-05-27T07:32:00"_toml;
BOOST_TEST(v1.is_local_datetime());
BOOST_TEST(toml::get<toml::local_datetime>(v1) ==
toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0)));
}
{
const toml::value v1 = "1979-05-27T07:32:00Z"_toml;
BOOST_TEST(v1.is_offset_datetime());
BOOST_TEST(toml::get<toml::offset_datetime>(v1) ==
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
}
}
BOOST_AUTO_TEST_CASE(test_file_as_u8_literal)
{
using namespace toml::literals::toml_literals;
{
const toml::value r{{"a", 42}, {"b", "baz"}};
const toml::value v = u8R"(
a = 42
b = "baz"
)"_toml;
BOOST_TEST(r == v);
}
{
const toml::value r{
{"c", 3.14},
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = u8R"(
c = 3.14
[table]
a = 42
b = "baz"
)"_toml;
BOOST_TEST(r == v);
}
{
const toml::value r{
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = u8R"(
[table]
a = 42
b = "baz"
)"_toml;
BOOST_TEST(r == v);
}
{
const toml::value r{
{"array_of_tables", toml::array{toml::table{}}}
};
const toml::value v = u8R"(
[[array_of_tables]]
)"_toml;
BOOST_TEST(r == v);
}
}
BOOST_AUTO_TEST_CASE(test_value_as_u8_literal)
{
using namespace toml::literals::toml_literals;
{
const toml::value v1 = u8"true"_toml;
const toml::value v2 = u8"false"_toml;
@@ -258,18 +98,15 @@ BOOST_AUTO_TEST_CASE(test_value_as_u8_literal)
const toml::value v2 = u8R"('foo')"_toml;
const toml::value v3 = u8R"("""foo""")"_toml;
const toml::value v4 = u8R"('''foo''')"_toml;
const toml::value v5 = u8R"("")"_toml;
BOOST_TEST(v1.is_string());
BOOST_TEST(v2.is_string());
BOOST_TEST(v3.is_string());
BOOST_TEST(v4.is_string());
BOOST_TEST(v5.is_string());
BOOST_TEST(toml::get<std::string>(v1) == "foo");
BOOST_TEST(toml::get<std::string>(v2) == "foo");
BOOST_TEST(toml::get<std::string>(v3) == "foo");
BOOST_TEST(toml::get<std::string>(v4) == "foo");
BOOST_TEST(toml::get<std::string>(v5) == "\xE3\x81\xB2\xE3\x82\x89\xE3\x81\x8C\xE3\x81\xAA");
}
{
{
@@ -327,7 +164,7 @@ BOOST_AUTO_TEST_CASE(test_value_as_u8_literal)
toml::local_time(7, 32, 0)));
}
{
const toml::value v1 = u8"1979-05-27T07:32:00Z"_toml;
const toml::value v1 = "1979-05-27T07:32:00Z"_toml;
BOOST_TEST(v1.is_offset_datetime());
BOOST_TEST(toml::get<toml::offset_datetime>(v1) ==
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "parse_array<toml::value>_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;
@@ -8,30 +13,30 @@ using namespace detail;
BOOST_AUTO_TEST_CASE(test_oneline_array)
{
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[]", array());
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[]", array());
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[3,1,4,1,5]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,1,4,1,5]", a);
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\"]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\"]", a);
}
{
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[3,1,4,1,5,]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,1,4,1,5,]", a);
}
{
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\",]", a);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\", \"bar\", \"baz\",]", a);
}
}
@@ -66,223 +71,60 @@ BOOST_AUTO_TEST_CASE(test_oneline_array_value)
BOOST_AUTO_TEST_CASE(test_multiline_array)
{
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value< discard_comments>>, "[\n#comment\n]", typename basic_value< discard_comments>::array_type());
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[\n#comment\n]", typename basic_value<preserve_comments>::array_type());
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\n#comment\n]", array());
{
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[3,\n1,\n4,\n1,\n5]", a);
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,\n1,\n4,\n1,\n5]", a);
}
{
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3);
a[1] = basic_value<preserve_comments>(1);
a[2] = basic_value<preserve_comments>(4);
a[3] = basic_value<preserve_comments>(1);
a[4] = basic_value<preserve_comments>(5);
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[3,\n1,\n4,\n1,\n5]", a);
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
}
{
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a);
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5]", a);
}
{
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3, {"comment"});
a[1] = basic_value<preserve_comments>(1, {"comment"});
a[2] = basic_value<preserve_comments>(4, {"comment"});
a[3] = basic_value<preserve_comments>(1, {"comment"});
a[4] = basic_value<preserve_comments>(5, {"comment"});
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", a);
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("bar");
a[2] = basic_value<discard_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo");
a[1] = basic_value<preserve_comments>("bar");
a[2] = basic_value<preserve_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", a);
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("b#r");
a[2] = basic_value<discard_comments>("b#z");
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<discard_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo", {"comment"});
a[1] = basic_value<preserve_comments>("b#r", {"comment"});
a[2] = basic_value<preserve_comments>("b#z", {"comment"});
TOML11_TEST_PARSE_EQUAL_VAT(parse_array<basic_value<preserve_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("b#r");
a[2] = toml::value("b#z");
TOML11_TEST_PARSE_EQUAL(parse_array<toml::value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", a);
}
}
BOOST_AUTO_TEST_CASE(test_multiline_array_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value< discard_comments>>, "[\n#comment\n]", basic_value< discard_comments>(typename basic_value< discard_comments>::array_type()));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\n#comment\n]", basic_value<preserve_comments>(typename basic_value<preserve_comments>::array_type()));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\n#comment\n]", toml::value(array()));
{
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[3,\n1,\n4,\n1,\n5]", basic_value<discard_comments>(a));
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[3,\n1,\n4,\n1,\n5]", toml::value(a));
}
{
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3);
a[1] = basic_value<preserve_comments>(1);
a[2] = basic_value<preserve_comments>(4);
a[3] = basic_value<preserve_comments>(1);
a[4] = basic_value<preserve_comments>(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[3,\n1,\n4,\n1,\n5]", basic_value<preserve_comments>(a));
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("bar");
a[2] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n\"bar\",\n\"baz\"]", toml::value(a));
}
{
typename basic_value<discard_comments>::array_type a(5);
a[0] = basic_value<discard_comments>(3);
a[1] = basic_value<discard_comments>(1);
a[2] = basic_value<discard_comments>(4);
a[3] = basic_value<discard_comments>(1);
a[4] = basic_value<discard_comments>(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value<discard_comments>(a));
array a(5);
a[0] = toml::value(3); a[1] = toml::value(1); a[2] = toml::value(4);
a[3] = toml::value(1); a[4] = toml::value(5);
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5]", toml::value(a));
}
{
typename basic_value<preserve_comments>::array_type a(5);
a[0] = basic_value<preserve_comments>(3, {"comment"});
a[1] = basic_value<preserve_comments>(1, {"comment"});
a[2] = basic_value<preserve_comments>(4, {"comment"});
a[3] = basic_value<preserve_comments>(1, {"comment"});
a[4] = basic_value<preserve_comments>(5, {"comment"});
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[3,#comment\n1,#comment\n4,#comment\n1,#comment\n5 #comment\n]", basic_value<preserve_comments>(a));
array a(3);
a[0] = toml::value("foo"); a[1] = toml::value("b#r");
a[2] = toml::value("b#z");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", toml::value(a));
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("bar");
a[2] = basic_value<discard_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value<discard_comments>(a));
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo");
a[1] = basic_value<preserve_comments>("bar");
a[2] = basic_value<preserve_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\"foo\",\n\"bar\",\n\"baz\"]", basic_value<preserve_comments>(a));
}
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("b#r");
a[2] = basic_value<discard_comments>("b#z");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value<discard_comments>(a));
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo", {"comment"});
a[1] = basic_value<preserve_comments>("b#r", {"comment"});
a[2] = basic_value<preserve_comments>("b#z", {"comment"});
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", basic_value<preserve_comments>(a));
}
}
BOOST_AUTO_TEST_CASE(test_heterogeneous_array)
{
#ifndef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("In strict TOML v0.5.0, heterogeneous arrays are not allowed.");
#else
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\", 3.14, 42, [\"array\", \"of\", \"hetero-array\", 1], {key = \"value\"}]", toml::value(a));
}
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\", \"of\", \"hetero-array\", 1],\n {key = \"value\"},\n]", toml::value(a));
}
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n 3.14,#comment\n 42,#comment\n [\"array\", \"of\", \"hetero-array\", 1],#comment\n {key = \"value\"},#comment\n]#comment", toml::value(a));
}
{
array a(5);
a[0] = toml::value("foo");
a[1] = toml::value(3.14);
a[2] = toml::value(42);
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
a[4] = toml::value{{"key", "value"}};
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\",\n \"of\",\n \"hetero-array\",\n 1],\n {key = \"value\"},\n]", toml::value(a));
}
#endif
}
BOOST_AUTO_TEST_CASE(test_comments_after_comma)
{
{
typename basic_value<discard_comments>::array_type a(3);
a[0] = basic_value<discard_comments>("foo");
a[1] = basic_value<discard_comments>("bar");
a[2] = basic_value<discard_comments>("baz");
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<discard_comments>>,
"[ \"foo\" # comment\n"
", \"bar\" # comment\n"
", \"baz\" # comment\n"
"]", basic_value<discard_comments>(a));
}
{
typename basic_value<preserve_comments>::array_type a(3);
a[0] = basic_value<preserve_comments>("foo", {" comment"});
a[1] = basic_value<preserve_comments>("bar", {" comment"});
a[2] = basic_value<preserve_comments>("baz", {" comment"});
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<basic_value<preserve_comments>>,
"[ \"foo\" # comment\n"
", \"bar\" # comment\n"
", \"baz\" # comment\n"
"]", basic_value<preserve_comments>(a));
}
}

View File

@@ -7,7 +7,7 @@
#define TOML11_TEST_PARSE_EQUAL(psr, tkn, expct) \
do { \
const std::string token(tkn); \
toml::detail::location loc("test", token); \
toml::detail::location<std::string> loc("test", token); \
const auto result = psr(loc); \
BOOST_TEST(result.is_ok()); \
if(result.is_ok()){ \
@@ -20,27 +20,11 @@ do { \
} while(false); \
/**/
#define TOML11_TEST_PARSE_EQUAL_VAT(psr, tkn, expct) \
do { \
const std::string token(tkn); \
toml::detail::location loc("test", token); \
const auto result = psr(loc, 0); \
BOOST_TEST(result.is_ok()); \
if(result.is_ok()){ \
BOOST_TEST(result.unwrap().first == expct); \
} else { \
std::cerr << "parser " << #psr << " failed with input `"; \
std::cerr << token << "`.\n"; \
std::cerr << "reason: " << result.unwrap_err() << '\n'; \
} \
} while(false); \
/**/
#define TOML11_TEST_PARSE_EQUAL_VALUE(psr, tkn, expct) \
do { \
const std::string token(tkn); \
toml::detail::location loc("test", token); \
const auto result = psr(loc, 0); \
toml::detail::location<std::string> loc("test", token); \
const auto result = psr(loc); \
BOOST_TEST(result.is_ok()); \
if(result.is_ok()){ \
BOOST_TEST(result.unwrap() == expct); \
@@ -51,4 +35,3 @@ do { \
} \
} while(false); \
/**/

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "test_parse_boolean"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "parse_datetime_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;
@@ -12,11 +17,6 @@ BOOST_AUTO_TEST_CASE(test_time)
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.99", toml::local_time(7, 32, 0, 990, 0));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999", toml::local_time(7, 32, 0, 999, 0));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "07:32:00.999999", toml::local_time(7, 32, 0, 999, 999));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "00:00:00.000000", toml::local_time( 0, 0, 0, 0, 0));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:59.999999", toml::local_time(23, 59, 59, 999, 999));
TOML11_TEST_PARSE_EQUAL(parse_local_time, "23:59:60.999999", toml::local_time(23, 59, 60, 999, 999)); // leap second
}
BOOST_AUTO_TEST_CASE(test_time_value)
@@ -25,125 +25,17 @@ BOOST_AUTO_TEST_CASE(test_time_value)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.99", toml::value(toml::local_time(7, 32, 0, 990, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999", toml::value(toml::local_time(7, 32, 0, 999, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "07:32:00.999999", toml::value(toml::local_time(7, 32, 0, 999, 999)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "00:00:00.000000", toml::value(toml::local_time( 0, 0, 0, 0, 0)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "23:59:59.999999", toml::value(toml::local_time(23, 59, 59, 999, 999)));
std::istringstream stream1(std::string("invalid-datetime = 24:00:00"));
std::istringstream stream2(std::string("invalid-datetime = 00:60:00"));
std::istringstream stream3(std::string("invalid-datetime = 00:00:61"));
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream3), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_date)
{
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27", toml::local_date(1979, toml::month_t::May, 27));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-01", toml::local_date(2000, toml::month_t::Jan, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-01-31", toml::local_date(2000, toml::month_t::Jan, 31));
std::istringstream stream1_1(std::string("invalid-datetime = 2000-01-00"));
std::istringstream stream1_2(std::string("invalid-datetime = 2000-01-32"));
BOOST_CHECK_THROW(toml::parse(stream1_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream1_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-01", toml::local_date(2000, toml::month_t::Feb, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-02-29", toml::local_date(2000, toml::month_t::Feb, 29));
std::istringstream stream2_1(std::string("invalid-datetime = 2000-02-00"));
std::istringstream stream2_2(std::string("invalid-datetime = 2000-02-30"));
BOOST_CHECK_THROW(toml::parse(stream2_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2001-02-28", toml::local_date(2001, toml::month_t::Feb, 28));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2004-02-29", toml::local_date(2004, toml::month_t::Feb, 29));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2100-02-28", toml::local_date(2100, toml::month_t::Feb, 28));
std::istringstream stream2_3(std::string("invalid-datetime = 2001-02-29"));
std::istringstream stream2_4(std::string("invalid-datetime = 2004-02-30"));
std::istringstream stream2_5(std::string("invalid-datetime = 2100-02-29"));
BOOST_CHECK_THROW(toml::parse(stream2_3), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2_4), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2_5), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-01", toml::local_date(2000, toml::month_t::Mar, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-03-31", toml::local_date(2000, toml::month_t::Mar, 31));
std::istringstream stream3_1(std::string("invalid-datetime = 2000-03-00"));
std::istringstream stream3_2(std::string("invalid-datetime = 2000-03-32"));
BOOST_CHECK_THROW(toml::parse(stream3_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream3_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-01", toml::local_date(2000, toml::month_t::Apr, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-04-30", toml::local_date(2000, toml::month_t::Apr, 30));
std::istringstream stream4_1(std::string("invalid-datetime = 2000-04-00"));
std::istringstream stream4_2(std::string("invalid-datetime = 2000-04-31"));
BOOST_CHECK_THROW(toml::parse(stream4_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream4_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-01", toml::local_date(2000, toml::month_t::May, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-05-31", toml::local_date(2000, toml::month_t::May, 31));
std::istringstream stream5_1(std::string("invalid-datetime = 2000-05-00"));
std::istringstream stream5_2(std::string("invalid-datetime = 2000-05-32"));
BOOST_CHECK_THROW(toml::parse(stream5_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream5_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-01", toml::local_date(2000, toml::month_t::Jun, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-06-30", toml::local_date(2000, toml::month_t::Jun, 30));
std::istringstream stream6_1(std::string("invalid-datetime = 2000-06-00"));
std::istringstream stream6_2(std::string("invalid-datetime = 2000-06-31"));
BOOST_CHECK_THROW(toml::parse(stream6_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream6_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-01", toml::local_date(2000, toml::month_t::Jul, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-07-31", toml::local_date(2000, toml::month_t::Jul, 31));
std::istringstream stream7_1(std::string("invalid-datetime = 2000-07-00"));
std::istringstream stream7_2(std::string("invalid-datetime = 2000-07-32"));
BOOST_CHECK_THROW(toml::parse(stream7_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream7_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-01", toml::local_date(2000, toml::month_t::Aug, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-08-31", toml::local_date(2000, toml::month_t::Aug, 31));
std::istringstream stream8_1(std::string("invalid-datetime = 2000-08-00"));
std::istringstream stream8_2(std::string("invalid-datetime = 2000-08-32"));
BOOST_CHECK_THROW(toml::parse(stream8_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream8_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-01", toml::local_date(2000, toml::month_t::Sep, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-09-30", toml::local_date(2000, toml::month_t::Sep, 30));
std::istringstream stream9_1(std::string("invalid-datetime = 2000-09-00"));
std::istringstream stream9_2(std::string("invalid-datetime = 2000-09-31"));
BOOST_CHECK_THROW(toml::parse(stream9_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream9_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-01", toml::local_date(2000, toml::month_t::Oct, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-10-31", toml::local_date(2000, toml::month_t::Oct, 31));
std::istringstream stream10_1(std::string("invalid-datetime = 2000-10-00"));
std::istringstream stream10_2(std::string("invalid-datetime = 2000-10-32"));
BOOST_CHECK_THROW(toml::parse(stream10_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream10_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-01", toml::local_date(2000, toml::month_t::Nov, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-11-30", toml::local_date(2000, toml::month_t::Nov, 30));
std::istringstream stream11_1(std::string("invalid-datetime = 2000-11-00"));
std::istringstream stream11_2(std::string("invalid-datetime = 2000-11-31"));
BOOST_CHECK_THROW(toml::parse(stream11_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream11_2), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-01", toml::local_date(2000, toml::month_t::Dec, 1));
TOML11_TEST_PARSE_EQUAL(parse_local_date, "2000-12-31", toml::local_date(2000, toml::month_t::Dec, 31));
std::istringstream stream12_1(std::string("invalid-datetime = 2000-12-00"));
std::istringstream stream12_2(std::string("invalid-datetime = 2000-12-32"));
BOOST_CHECK_THROW(toml::parse(stream12_1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream12_2), toml::syntax_error);
std::istringstream stream13_1(std::string("invalid-datetime = 2000-13-01"));
BOOST_CHECK_THROW(toml::parse(stream13_1), toml::syntax_error);
std::istringstream stream0_1(std::string("invalid-datetime = 2000-00-01"));
BOOST_CHECK_THROW(toml::parse(stream0_1), toml::syntax_error);
TOML11_TEST_PARSE_EQUAL(parse_local_date, "1979-05-27",
toml::local_date(1979, toml::month_t::May, 27));
}
BOOST_AUTO_TEST_CASE(test_date_value)
{
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27", value(toml::local_date(1979, toml::month_t::May, 27)));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1979-05-27",
value(toml::local_date(1979, toml::month_t::May, 27)));
}
BOOST_AUTO_TEST_CASE(test_datetime)
@@ -215,11 +107,6 @@ BOOST_AUTO_TEST_CASE(test_offset_datetime)
TOML11_TEST_PARSE_EQUAL(parse_offset_datetime, "1979-05-27T07:32:00.999999+09:00",
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0, 999, 999), toml::time_offset(9, 0)));
std::istringstream stream1(std::string("invalid-datetime = 2000-01-01T00:00:00+24:00"));
std::istringstream stream2(std::string("invalid-datetime = 2000-01-01T00:00:00+00:60"));
BOOST_CHECK_THROW(toml::parse(stream1), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(stream2), toml::syntax_error);
}
BOOST_AUTO_TEST_CASE(test_offset_datetime_value)

View File

@@ -1,15 +1,19 @@
#define BOOST_TEST_MODULE "test_parse_file"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <deque>
#include <fstream>
#include <iostream>
#include <fstream>
#include <map>
#include <deque>
BOOST_AUTO_TEST_CASE(test_example)
{
const auto data = toml::parse(testinput("example.toml"));
const auto data = toml::parse("toml/tests/example.toml");
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
@@ -72,7 +76,7 @@ BOOST_AUTO_TEST_CASE(test_example)
BOOST_AUTO_TEST_CASE(test_example_stream)
{
std::ifstream ifs(testinput("example.toml"), std::ios::binary);
std::ifstream ifs("toml/tests/example.toml");
const auto data = toml::parse(ifs);
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
@@ -138,78 +142,9 @@ BOOST_AUTO_TEST_CASE(test_example_stream)
}
}
BOOST_AUTO_TEST_CASE(test_example_file_pointer)
{
FILE * file = fopen(testinput("example.toml").c_str(), "rb");
const auto data = toml::parse(file, "toml/tests/example.toml");
fclose(file);
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
{
BOOST_TEST(toml::find<std::string>(owner, "name") == "Tom Preston-Werner");
BOOST_TEST(toml::find<std::string>(owner, "organization") == "GitHub");
BOOST_TEST(toml::find<std::string>(owner, "bio") ==
"GitHub Cofounder & CEO\nLikes tater tots and beer.");
BOOST_TEST(toml::find<toml::offset_datetime>(owner, "dob") ==
toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27),
toml::local_time(7, 32, 0), toml::time_offset(0, 0)));
}
const auto& database = toml::find(data, "database");
{
BOOST_TEST(toml::find<std::string>(database, "server") == "192.168.1.1");
const std::vector<int> expected_ports{8001, 8001, 8002};
BOOST_CHECK(toml::find<std::vector<int>>(database, "ports") == expected_ports);
BOOST_TEST(toml::find<int >(database, "connection_max") == 5000);
BOOST_TEST(toml::find<bool>(database, "enabled") == true);
}
const auto& servers = toml::find(data, "servers");
{
toml::table alpha = toml::find<toml::table>(servers, "alpha");
BOOST_TEST(toml::get<std::string>(alpha.at("ip")) == "10.0.0.1");
BOOST_TEST(toml::get<std::string>(alpha.at("dc")) == "eqdc10");
toml::table beta = toml::find<toml::table>(servers, "beta");
BOOST_TEST(toml::get<std::string>(beta.at("ip")) == "10.0.0.2");
BOOST_TEST(toml::get<std::string>(beta.at("dc")) == "eqdc10");
BOOST_TEST(toml::get<std::string>(beta.at("country")) == "\xE4\xB8\xAD\xE5\x9B\xBD");
}
const auto& clients = toml::find(data, "clients");
{
toml::array clients_data = toml::find<toml::array>(clients, "data");
std::vector<std::string> expected_name{"gamma", "delta"};
BOOST_CHECK(toml::get<std::vector<std::string>>(clients_data.at(0)) == expected_name);
std::vector<int> expected_number{1, 2};
BOOST_CHECK(toml::get<std::vector<int>>(clients_data.at(1)) == expected_number);
std::vector<std::string> expected_hosts{"alpha", "omega"};
BOOST_CHECK(toml::find<std::vector<std::string>>(clients, "hosts") == expected_hosts);
}
std::vector<toml::table> products =
toml::find<std::vector<toml::table>>(data, "products");
{
BOOST_TEST(toml::get<std::string>(products.at(0).at("name")) ==
"Hammer");
BOOST_TEST(toml::get<std::int64_t>(products.at(0).at("sku")) ==
738594937);
BOOST_TEST(toml::get<std::string>(products.at(1).at("name")) ==
"Nail");
BOOST_TEST(toml::get<std::int64_t>(products.at(1).at("sku")) ==
284758393);
BOOST_TEST(toml::get<std::string>(products.at(1).at("color")) ==
"gray");
}
}
BOOST_AUTO_TEST_CASE(test_fruit)
{
const auto data = toml::parse(testinput("fruit.toml"));
const auto data = toml::parse("toml/tests/fruit.toml");
const auto blah = toml::find<toml::array>(toml::find(data, "fruit"), "blah");
BOOST_TEST(toml::find<std::string>(blah.at(0), "name") == "apple");
BOOST_TEST(toml::find<std::string>(blah.at(1), "name") == "banana");
@@ -227,7 +162,7 @@ BOOST_AUTO_TEST_CASE(test_fruit)
BOOST_AUTO_TEST_CASE(test_hard_example)
{
const auto data = toml::parse(testinput("hard_example.toml"));
const auto data = toml::parse("toml/tests/hard_example.toml");
const auto the = toml::find(data, "the");
BOOST_TEST(toml::find<std::string>(the, "test_string") ==
"You'll hate me after this - #");
@@ -254,7 +189,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
}
BOOST_AUTO_TEST_CASE(test_hard_example_comment)
{
const auto data = toml::parse<toml::preserve_comments>(testinput("hard_example.toml"));
const auto data = toml::parse<toml::preserve_comments>("toml/tests/hard_example.toml");
const auto the = toml::find(data, "the");
BOOST_TEST(toml::find<std::string>(the, "test_string") ==
"You'll hate me after this - #");
@@ -283,7 +218,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example_comment)
BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
{
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
@@ -365,8 +300,8 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
testinput("example.toml"));
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque
>("toml/tests/example.toml");
static_assert(std::is_same<typename decltype(data)::table_type,
std::map<toml::key, typename std::remove_cv<decltype(data)>::type>
@@ -844,22 +779,6 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// without newline
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"a = 0"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
// CRLF
@@ -970,40 +889,3 @@ BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
}
}
BOOST_AUTO_TEST_CASE(test_file_ends_without_lf)
{
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\""
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_without_lf.toml");
BOOST_TEST(toml::find<std::string>(data, "key") == "value");
BOOST_TEST(toml::find<std::string>(toml::find(data, "table"), "key") == "value");
}
}
BOOST_AUTO_TEST_CASE(test_parse_function_compiles)
{
using result_type = decltype(toml::parse("string literal"));
(void) [](const char* that) -> result_type { return toml::parse(that); };
(void) [](char* that) -> result_type { return toml::parse(that); };
(void) [](const std::string& that) -> result_type { return toml::parse(that); };
(void) [](std::string& that) -> result_type { return toml::parse(that); };
(void) [](std::string&& that) -> result_type { return toml::parse(that); };
#ifdef TOML11_HAS_STD_FILESYSTEM
(void) [](const std::filesystem::path& that) -> result_type { return toml::parse(that); };
(void) [](std::filesystem::path& that) -> result_type { return toml::parse(that); };
(void) [](std::filesystem::path&& that) -> result_type { return toml::parse(that); };
#endif
(void) [](std::FILE* that) -> result_type { return toml::parse(that, "mandatory.toml"); };
}
BOOST_AUTO_TEST_CASE(test_parse_nonexistent_file)
{
BOOST_CHECK_THROW(toml::parse("nonexistent.toml"), std::ios_base::failure);
}

View File

@@ -1,9 +1,13 @@
#define BOOST_TEST_MODULE "parse_floating_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
#include <cmath>
#include "test_parse_aux.hpp"
using namespace toml;
using namespace detail;
@@ -64,13 +68,6 @@ BOOST_AUTO_TEST_CASE(test_exponential)
TOML11_TEST_PARSE_EQUAL(parse_floating, "1_2_3E-1_0", 123e-10);
TOML11_TEST_PARSE_EQUAL(parse_floating, "+0e0", 0.0);
TOML11_TEST_PARSE_EQUAL(parse_floating, "-0e0", -0.0);
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_PARSE_EQUAL(parse_floating, "1_2_3E-01", 123e-1);
TOML11_TEST_PARSE_EQUAL(parse_floating, "1_2_3E-0_1", 123e-1);
#endif
}
BOOST_AUTO_TEST_CASE(test_exponential_value)
@@ -93,13 +90,6 @@ BOOST_AUTO_TEST_CASE(test_exponential_value)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3E-1_0", value(123e-10));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "+0e0", value( 0.0));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "-0e0", value(-0.0));
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3E-01", value(123e-1));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1_2_3E-0_1", value(123e-1));
#endif
}
BOOST_AUTO_TEST_CASE(test_fe)
{
@@ -112,19 +102,13 @@ BOOST_AUTO_TEST_CASE(test_fe_vaule)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "6.02e23", value(6.02e23));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "6.02e+23", value(6.02e23));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "1.112_650_06e-17", value(1.11265006e-17));
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
BOOST_TEST_MESSAGE("testing an unreleased toml feature: leading zeroes in float exponent part");
// toml-lang/toml master permits leading 0s in exp part (unreleased)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "3.141_5e-01", value(3.1415e-1));
#endif
}
BOOST_AUTO_TEST_CASE(test_inf)
{
{
const std::string token("inf");
toml::detail::location loc("test", token);
toml::detail::location<std::string> loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isinf(r.unwrap().first));
@@ -132,7 +116,7 @@ BOOST_AUTO_TEST_CASE(test_inf)
}
{
const std::string token("+inf");
toml::detail::location loc("test", token);
toml::detail::location<std::string> loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isinf(r.unwrap().first));
@@ -140,7 +124,7 @@ BOOST_AUTO_TEST_CASE(test_inf)
}
{
const std::string token("-inf");
toml::detail::location loc("test", token);
toml::detail::location<std::string> loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isinf(r.unwrap().first));
@@ -152,30 +136,23 @@ BOOST_AUTO_TEST_CASE(test_nan)
{
{
const std::string token("nan");
toml::detail::location loc("test", token);
toml::detail::location<std::string> loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isnan(r.unwrap().first));
}
{
const std::string token("+nan");
toml::detail::location loc("test", token);
toml::detail::location<std::string> loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isnan(r.unwrap().first));
}
{
const std::string token("-nan");
toml::detail::location loc("test", token);
toml::detail::location<std::string> loc("test", token);
const auto r = parse_floating(loc);
BOOST_CHECK(r.is_ok());
BOOST_CHECK(std::isnan(r.unwrap().first));
}
}
BOOST_AUTO_TEST_CASE(test_overflow)
{
std::istringstream float_overflow (std::string("float-overflow = 1.0e+1024"));
BOOST_CHECK_THROW(toml::parse(float_overflow ), toml::syntax_error);
// istringstream >> float does not set failbit in case of underflow.
}

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "parse_inline_table_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;
@@ -8,19 +13,19 @@ using namespace detail;
BOOST_AUTO_TEST_CASE(test_inline_table)
{
TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table<toml::value>, "{}", table());
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{}", table());
{
table t;
t["foo"] = toml::value(42);
t["bar"] = toml::value("baz");
TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table<toml::value>, "{foo = 42, bar = \"baz\"}", t);
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{foo = 42, bar = \"baz\"}", t);
}
{
table t;
table t_sub;
t_sub["name"] = toml::value("pug");
t["type"] = toml::value(t_sub);
TOML11_TEST_PARSE_EQUAL_VAT(parse_inline_table<toml::value>, "{type.name = \"pug\"}", t);
TOML11_TEST_PARSE_EQUAL(parse_inline_table<toml::value>, "{type.name = \"pug\"}", t);
}
}
@@ -41,19 +46,3 @@ BOOST_AUTO_TEST_CASE(test_inline_table_value)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "{type.name = \"pug\"}", value(t));
}
}
BOOST_AUTO_TEST_CASE(test_inline_table_immutability)
{
{
std::istringstream stream(std::string(
"a = {b = 1}\n"
"a.c = 2\n"));
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
{
std::istringstream stream(std::string(
"a = {b = {c = 1}}\n"
"a.b.d = 2\n"));
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
}
}

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "parse_integer_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;
@@ -84,33 +89,4 @@ BOOST_AUTO_TEST_CASE(test_bin_value)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b010000", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b01_00_00", value(16));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "0b111111", value(63));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"0b1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000_1000",
// 1 0 0 0
// 0 C 8 4
value(0x0888888888888888));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"0b01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111",
// 1 0 0 0
// 0 C 8 4
value(0x7FFFFFFFFFFFFFFF));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"0b00000000_01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111",
// 1 0 0 0
// 0 C 8 4
value(0x7FFFFFFFFFFFFFFF));
}
BOOST_AUTO_TEST_CASE(test_integer_overflow)
{
std::istringstream dec_overflow(std::string("dec-overflow = 9223372036854775808"));
std::istringstream hex_overflow(std::string("hex-overflow = 0x1_00000000_00000000"));
std::istringstream oct_overflow(std::string("oct-overflow = 0o1_000_000_000_000_000_000_000"));
// 64 56 48 40 32 24 16 8
std::istringstream bin_overflow(std::string("bin-overflow = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000"));
BOOST_CHECK_THROW(toml::parse(dec_overflow), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(hex_overflow), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(oct_overflow), toml::syntax_error);
BOOST_CHECK_THROW(toml::parse(bin_overflow), toml::syntax_error);
}

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "parse_key_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "parse_string_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;
@@ -64,9 +69,6 @@ BOOST_AUTO_TEST_CASE(test_basic_string)
TOML11_TEST_PARSE_EQUAL(parse_string,
"\" And when \\\"'s are in the along with # \\\"\"",
string(" And when \"'s are in the along with # \"", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"Here are fifteen apostrophes: '''''''''''''''\"",
string("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_basic_string_value)
@@ -92,9 +94,6 @@ BOOST_AUTO_TEST_CASE(test_basic_string_value)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\" And when \\\"'s are in the along with # \\\"\"",
value(" And when \"'s are in the along with # \"", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"Here are fifteen apostrophes: '''''''''''''''\"",
value("Here are fifteen apostrophes: '''''''''''''''", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_ml_basic_string)
@@ -105,18 +104,6 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string)
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
string("The quick brown fox jumps over the lazy dog.", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
string("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
string("Here are three quotation marks: \"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL(parse_string,
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
string("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_ml_basic_string_value)
@@ -127,19 +114,6 @@ BOOST_AUTO_TEST_CASE(test_ml_basic_string_value)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"\\\n The quick brown \\\n\n fox jumps over \\\n the lazy dog.\\\n \"\"\"",
value("The quick brown fox jumps over the lazy dog.", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"",
value("Here are two quotation marks: \"\". Simple enough.", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"Here are three quotation marks: \"\"\\\".\"\"\"",
value("Here are three quotation marks: \"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"",
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::basic));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"\"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\"",
value("\"This,\" she said, \"is just a pointless statement.\"", string_t::basic));
}
BOOST_AUTO_TEST_CASE(test_literal_string)
@@ -182,15 +156,6 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string)
TOML11_TEST_PARSE_EQUAL(parse_string,
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
string("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
TOML11_TEST_PARSE_EQUAL(parse_string,
"''''That's still pointless', she said.'''",
string("'That's still pointless', she said.", string_t::literal));
TOML11_TEST_PARSE_EQUAL(parse_string,
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
string("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
TOML11_TEST_PARSE_EQUAL(parse_string,
"''''This,' she said, 'is just a pointless statement.''''",
string("'This,' she said, 'is just a pointless statement.'", string_t::literal));
}
BOOST_AUTO_TEST_CASE(test_ml_literal_string_value)
@@ -201,30 +166,8 @@ BOOST_AUTO_TEST_CASE(test_ml_literal_string_value)
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'''\nThe first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n'''",
value("The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"''''That's still pointless', she said.'''",
value("'That's still pointless', she said.", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"'''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".'''",
value("Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", string_t::literal));
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>,
"''''This,' she said, 'is just a pointless statement.''''",
value("'This,' she said, 'is just a pointless statement.'", string_t::literal));
}
BOOST_AUTO_TEST_CASE(test_simple_excape_sequences)
{
TOML11_TEST_PARSE_EQUAL(parse_string,
R"("\"\\\b\f\n\r\t")",
string("\"\\\b\f\n\r\t", string_t::basic));
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
TOML11_TEST_PARSE_EQUAL(parse_string,
R"("\e")",
string("\x1b", string_t::basic));
#endif
}
BOOST_AUTO_TEST_CASE(test_unicode_escape_sequence)
{
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)

View File

@@ -1,7 +1,12 @@
#include <toml/get.hpp>
#define BOOST_TEST_MODULE "parse_table_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include <toml/get.hpp>
#include "test_parse_aux.hpp"
using namespace toml;
@@ -14,7 +19,7 @@ BOOST_AUTO_TEST_CASE(test_normal_table)
"key2 = 42\n"
"key3 = 3.14\n"
);
location loc("test", table);
location<std::string> loc("test", table);
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
BOOST_TEST(result.is_ok());
@@ -31,7 +36,7 @@ BOOST_AUTO_TEST_CASE(test_nested_table)
"a.b = \"value\"\n"
"a.c.d = 42\n"
);
location loc("test", table);
location<std::string> loc("test", table);
const auto result = toml::detail::parse_ml_table<toml::value>(loc);
BOOST_TEST(result.is_ok());

View File

@@ -1,6 +1,11 @@
#define BOOST_TEST_MODULE "parse_table_key_test"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/parser.hpp>
#include "unit_test.hpp"
#include "test_parse_aux.hpp"
using namespace toml;

View File

@@ -1,13 +1,18 @@
#define BOOST_TEST_MODULE "test_parse_unicode"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <fstream>
#include <iostream>
#include <fstream>
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
{
const auto data = toml::parse(testinput("hard_example_unicode.toml"));
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
const auto the = toml::find<toml::table>(data, "the");
BOOST_TEST(toml::get<std::string>(the.at("test_string")) ==
@@ -35,3 +40,35 @@ BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
expected_multi_line_array);
}
#else
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
{
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
const auto the = toml::find<toml::table>(data, "the");
BOOST_TEST(toml::get<std::string>(the.at("test_string")) ==
std::string(u8"Ýôú' λáƭè ₥è áƒƭèř ƭλïƨ - #"));
const auto hard = toml::get<toml::table>(the.at("hard"));
const std::vector<std::string> expected_the_hard_test_array{"] ", " # "};
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array")) ==
expected_the_hard_test_array);
const std::vector<std::string> expected_the_hard_test_array2{
std::string(u8"Tèƨƭ #11 ]ƥřôƲèδ ƭλáƭ"),
std::string(u8"Éжƥèřï₥èñƭ #9 ωáƨ á ƨúççèƨƨ")};
BOOST_CHECK(toml::get<std::vector<std::string>>(hard.at("test_array2")) ==
expected_the_hard_test_array2);
BOOST_TEST(toml::get<std::string>(hard.at("another_test_string")) ==
std::string(u8"§á₥è ƭλïñϱ, βúƭ ωïƭλ á ƨƭřïñϱ #"));
BOOST_TEST(toml::get<std::string>(hard.at("harder_test_string")) ==
std::string(u8" Âñδ ωλèñ \"'ƨ ářè ïñ ƭλè ƨƭřïñϱ, áℓôñϱ ωïƭλ # \""));
const auto bit = toml::get<toml::table>(hard.at(std::string(u8"βïƭ#")));
BOOST_TEST(toml::get<std::string>(bit.at(std::string(u8"ωλáƭ?"))) ==
std::string(u8"Ýôú δôñ'ƭ ƭλïñƙ ƨô₥è úƨèř ωôñ'ƭ δô ƭλáƭ?"));
const std::vector<std::string> expected_multi_line_array{"]"};
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
expected_multi_line_array);
}
#endif

View File

@@ -1,8 +1,7 @@
#include <toml/result.hpp>
#include "unit_test.hpp"
#define BOOST_TEST_MODULE "test_result"
#include <boost/test/unit_test.hpp>
#include <iostream>
#include <toml/result.hpp>
BOOST_AUTO_TEST_CASE(test_construct)
{
@@ -438,3 +437,5 @@ BOOST_AUTO_TEST_CASE(test_and_or_other)
BOOST_TEST("foo" == r1_gen().and_other(r2_gen()).unwrap_err());
}
}

View File

@@ -1,14 +1,15 @@
#define BOOST_TEST_MODULE "test_serialize_file"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <deque>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <clocale>
#include <iostream>
#include <fstream>
template<typename Comment,
template<typename ...> class Table,
@@ -45,7 +46,7 @@ bool has_comment_inside(const toml::basic_value<Comment, Table, Array>& v)
BOOST_AUTO_TEST_CASE(test_example)
{
const auto data = toml::parse(testinput("example.toml"));
const auto data = toml::parse("toml/tests/example.toml");
{
std::ofstream ofs("tmp1.toml");
ofs << std::setw(80) << data;
@@ -67,7 +68,7 @@ BOOST_AUTO_TEST_CASE(test_example)
BOOST_AUTO_TEST_CASE(test_example_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
testinput("example.toml"));
"toml/tests/example.toml");
{
std::ofstream ofs("tmp1_map_dq.toml");
ofs << std::setw(80) << data;
@@ -89,7 +90,7 @@ BOOST_AUTO_TEST_CASE(test_example_map_dq)
BOOST_AUTO_TEST_CASE(test_example_with_comment)
{
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
{
std::ofstream ofs("tmp1_com.toml");
ofs << std::setw(80) << data;
@@ -115,7 +116,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment)
BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
{
{
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
{
std::ofstream ofs("tmp1_com_nocomment.toml");
ofs << std::setw(80) << toml::nocomment << data;
@@ -125,8 +126,8 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
BOOST_TEST(!has_comment_inside(serialized));
}
{
const auto data_nocomment = toml::parse<toml::discard_comments>(testinput("example.toml"));
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_nocomment.toml");
const auto data_nocomment = toml::parse("toml/tests/example.toml");
auto serialized = toml::parse("tmp1_com_nocomment.toml");
{
auto& owner = toml::find(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
@@ -144,7 +145,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
testinput("example.toml"));
"toml/tests/example.toml");
{
std::ofstream ofs("tmp1_com_map_dq.toml");
ofs << std::setw(80) << data;
@@ -171,7 +172,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq)
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
{
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(testinput("example.toml"));
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>("toml/tests/example.toml");
{
std::ofstream ofs("tmp1_com_map_dq_nocomment.toml");
ofs << std::setw(80) << toml::nocomment << data;
@@ -180,8 +181,8 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
BOOST_TEST(!has_comment_inside(serialized));
}
{
const auto data_nocomment = toml::parse<toml::discard_comments>(testinput("example.toml"));
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_map_dq_nocomment.toml");
const auto data_nocomment = toml::parse("toml/tests/example.toml");
auto serialized = toml::parse("tmp1_com_map_dq_nocomment.toml");
{
auto& owner = toml::find(serialized, "owner");
auto& bio = toml::find<std::string>(owner, "bio");
@@ -197,7 +198,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
BOOST_AUTO_TEST_CASE(test_fruit)
{
const auto data = toml::parse(testinput("fruit.toml"));
const auto data = toml::parse("toml/tests/fruit.toml");
{
std::ofstream ofs("tmp2.toml");
ofs << std::setw(80) << data;
@@ -209,7 +210,7 @@ BOOST_AUTO_TEST_CASE(test_fruit)
BOOST_AUTO_TEST_CASE(test_fruit_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
testinput("fruit.toml"));
"toml/tests/fruit.toml");
{
std::ofstream ofs("tmp2.toml");
ofs << std::setw(80) << data;
@@ -221,7 +222,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_map_dq)
BOOST_AUTO_TEST_CASE(test_fruit_with_comments)
{
const auto data = toml::parse<toml::preserve_comments>(testinput("fruit.toml"));
const auto data = toml::parse<toml::preserve_comments>("toml/tests/fruit.toml");
{
std::ofstream ofs("tmp2_com.toml");
ofs << std::setw(80) << data;
@@ -233,7 +234,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_with_comments)
BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
testinput("fruit.toml"));
"toml/tests/fruit.toml");
{
std::ofstream ofs("tmp2_com.toml");
ofs << std::setw(80) << data;
@@ -244,7 +245,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq)
BOOST_AUTO_TEST_CASE(test_hard_example)
{
const auto data = toml::parse(testinput("hard_example.toml"));
const auto data = toml::parse("toml/tests/hard_example.toml");
{
std::ofstream ofs("tmp3.toml");
ofs << std::setw(80) << data;
@@ -256,7 +257,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
BOOST_AUTO_TEST_CASE(test_hard_example_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
testinput("hard_example.toml"));
"toml/tests/hard_example.toml");
{
std::ofstream ofs("tmp3.toml");
ofs << std::setw(80) << data;
@@ -269,7 +270,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example_map_dq)
BOOST_AUTO_TEST_CASE(test_hard_example_with_comment)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
testinput("hard_example.toml"));
"toml/tests/hard_example.toml");
{
std::ofstream ofs("tmp3_com.toml");
ofs << std::setw(80) << data;
@@ -302,104 +303,3 @@ BOOST_AUTO_TEST_CASE(test_format_key)
BOOST_TEST("\"special-chars-\\\\-\\\"-\\b-\\f-\\r-\\n-\\t\"" == toml::format_key(key));
}
}
// In toml11, an implicitly-defined value does not have any comments.
// So, in the following file,
// ```toml
// # comment
// [[array-of-tables]]
// foo = "bar"
// ```
// The array named "array-of-tables" does not have the comment, but the first
// element of the array has. That means that, the above file is equivalent to
// the following.
// ```toml
// array-of-tables = [
// # comment
// {foo = "bar"},
// ]
// ```
// If the array itself has a comment (value_has_comment_ == true), we should try
// to make it inline.
// ```toml
// # comment about array
// array-of-tables = [
// # comment about table element
// {foo = "bar"}
// ]
// ```
// If it is formatted as a multiline table, the two comments becomes
// indistinguishable.
// ```toml
// # comment about array
// # comment about table element
// [[array-of-tables]]
// foo = "bar"
// ```
// So we need to try to make it inline, and it force-inlines regardless
// of the line width limit.
// It may fail if the element of a table has comment. In that case,
// the array-of-tables will be formatted as a multiline table.
BOOST_AUTO_TEST_CASE(test_distinguish_comment)
{
const std::string str = R"(# comment about array itself
array_of_table = [
# comment about the first element (table)
{key = "value"},
])";
std::istringstream iss(str);
const auto data = toml::parse<toml::preserve_comments>(iss);
const auto serialized = toml::format(data, /*width = */ 0);
std::istringstream reparse(serialized);
const auto parsed = toml::parse<toml::preserve_comments>(reparse);
BOOST_TEST(parsed.at("array_of_table").comments().size() == 1u);
BOOST_TEST(parsed.at("array_of_table").comments().front() == " comment about array itself");
BOOST_TEST(parsed.at("array_of_table").at(0).comments().size() == 1u);
BOOST_TEST(parsed.at("array_of_table").at(0).comments().front() == " comment about the first element (table)");
}
BOOST_AUTO_TEST_CASE(test_serialize_under_locale)
{
// avoid null init (setlocale returns null when it failed)
std::string setloc(std::setlocale(LC_ALL, nullptr));
// fr_FR is a one of locales that uses `,` as a decimal separator.
if(const char* try_hyphen = std::setlocale(LC_ALL, "fr_FR.UTF-8"))
{
setloc = std::string(try_hyphen);
}
else if(const char* try_nohyphen = std::setlocale(LC_ALL, "fr_FR.utf8"))
{
setloc = std::string(try_nohyphen);
}
// In some envs, fr_FR locale has not been installed. Tests must work even in such a case.
// else
// {
// BOOST_TEST(false);
// }
BOOST_TEST_MESSAGE("current locale at the beginning of the test = " << setloc);
const std::string str = R"(
pi = 3.14159
large_int = 1234567890
)";
std::istringstream iss(str);
const auto ref = toml::parse(iss);
const auto serialized_str = toml::format(ref, /*width = */ 80);
BOOST_TEST_MESSAGE("serialized = " << serialized_str);
std::istringstream serialized_iss(serialized_str);
const auto serialized_ref = toml::parse(serialized_iss);
BOOST_TEST(serialized_ref.at("pi").as_floating() == ref.at("pi").as_floating());
BOOST_TEST(serialized_ref.at("large_int").as_integer() == ref.at("large_int").as_integer());
const std::string endloc(std::setlocale(LC_ALL, nullptr));
BOOST_TEST_MESSAGE("current locale at the end of the test = " << endloc);
// check if serializer change global locale
BOOST_TEST(setloc == endloc);
}

View File

@@ -1,7 +1,7 @@
#define BOOST_TEST_MODULE "test_string"
#include <boost/test/unit_test.hpp>
#include <toml.hpp>
#include "unit_test.hpp"
BOOST_AUTO_TEST_CASE(test_basic_string)
{
{
@@ -111,43 +111,3 @@ BOOST_AUTO_TEST_CASE(test_literal_ml_string)
}
}
BOOST_AUTO_TEST_CASE(test_string_add_assign)
{
// string literal
{
toml::string str("foo");
str += "bar";
BOOST_TEST(str.str == "foobar");
}
// std::string
{
toml::string str("foo");
std::string str2("bar");
str += str2;
BOOST_TEST(str.str == "foobar");
}
// toml::string
{
toml::string str("foo");
toml::string str2("bar");
str += str2;
BOOST_TEST(str.str == "foobar");
}
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
// std::string_view
{
toml::string str("foo");
str += std::string_view("bar");
BOOST_TEST(str == "foobar");
}
#endif
// std::string += toml::string
{
std::string str("foo");
toml::string str2("bar");
str += str2;
BOOST_TEST(str == "foobar");
}
}

View File

@@ -1,16 +1,21 @@
#define BOOST_TEST_MODULE "test_traits"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/types.hpp>
#include "unit_test.hpp"
#include <array>
#include <deque>
#include <forward_list>
#include <list>
#include <forward_list>
#include <deque>
#include <array>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <string>
struct dummy_type{};

View File

@@ -1,28 +1,35 @@
#define BOOST_TEST_MODULE "test_acceptor"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml/utility.hpp>
#include "unit_test.hpp"
#include <array>
#include <vector>
#include <array>
BOOST_AUTO_TEST_CASE(test_try_reserve)
BOOST_AUTO_TEST_CASE(test_resize)
{
{
// since BOOST_TEST is a macro, it cannot handle commas correctly.
// When toml::detail::has_reserve_method<std::array<int, 1>>::value
// is passed to a macro, C preprocessor considers
// toml::detail::has_reserve_method<std::array<int as the first argument
// and 1>>::value as the second argument. We need an alias to avoid
// this problem.
using reservable_type = std::vector<int> ;
using nonreservable_type = std::array<int, 1>;
BOOST_TEST( toml::detail::has_reserve_method<reservable_type >::value);
BOOST_TEST(!toml::detail::has_reserve_method<nonreservable_type>::value);
typedef std::vector<int> resizable_type;
typedef std::array<int,1> non_resizable_type;
BOOST_TEST(toml::detail::has_resize_method<resizable_type>::value);
BOOST_TEST(!toml::detail::has_resize_method<non_resizable_type>::value);
}
{
std::vector<int> v;
toml::try_reserve(v, 100);
BOOST_TEST(v.capacity() == 100u);
toml::resize(v, 10);
BOOST_TEST(v.size() == 10u);
}
{
std::array<int, 15> a;
toml::resize(a, 10);
BOOST_TEST(a.size() == 15u);
}
{
std::array<int, 15> a;
BOOST_CHECK_THROW(toml::resize(a, 20), std::invalid_argument);
}
}

View File

@@ -1,11 +1,15 @@
#define BOOST_TEST_MODULE "test_value"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include "unit_test.hpp"
#include <map>
#include <list>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __cplusplus >= 201703L
#include <string_view>
#endif
@@ -419,7 +423,7 @@ BOOST_AUTO_TEST_CASE(test_value_string)
BOOST_TEST(v2.as_boolean() == true);
BOOST_TEST(v3.as_boolean() == true);
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __cplusplus >= 201703L
std::string_view sv = "foo";
toml::value v7(sv);
@@ -901,115 +905,3 @@ BOOST_AUTO_TEST_CASE(test_value_empty)
BOOST_CHECK_THROW(v1.as_array(), toml::type_error);
BOOST_CHECK_THROW(v1.as_table(), toml::type_error);
}
BOOST_AUTO_TEST_CASE(test_value_at)
{
{
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
BOOST_TEST(v1.at("foo").as_integer() == 42);
BOOST_TEST(v1.at("bar").as_floating() == 3.14);
BOOST_TEST(v1.at("baz").as_string() == "qux");
BOOST_CHECK_THROW(v1.at(0), toml::type_error);
BOOST_CHECK_THROW(v1.at("quux"), std::out_of_range);
}
{
toml::value v1{1,2,3,4,5};
BOOST_TEST(v1.at(0).as_integer() == 1);
BOOST_TEST(v1.at(1).as_integer() == 2);
BOOST_TEST(v1.at(2).as_integer() == 3);
BOOST_TEST(v1.at(3).as_integer() == 4);
BOOST_TEST(v1.at(4).as_integer() == 5);
BOOST_CHECK_THROW(v1.at("foo"), toml::type_error);
BOOST_CHECK_THROW(v1.at(5), std::out_of_range);
}
}
BOOST_AUTO_TEST_CASE(test_value_bracket)
{
{
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
BOOST_TEST(v1["foo"].as_integer() == 42);
BOOST_TEST(v1["bar"].as_floating() == 3.14);
BOOST_TEST(v1["baz"].as_string() == "qux");
v1["qux"] = 54;
BOOST_TEST(v1["qux"].as_integer() == 54);
}
{
toml::value v1;
v1["foo"] = 42;
BOOST_TEST(v1.is_table());
BOOST_TEST(v1["foo"].as_integer() == 42);
}
{
toml::value v1{1,2,3,4,5};
BOOST_TEST(v1[0].as_integer() == 1);
BOOST_TEST(v1[1].as_integer() == 2);
BOOST_TEST(v1[2].as_integer() == 3);
BOOST_TEST(v1[3].as_integer() == 4);
BOOST_TEST(v1[4].as_integer() == 5);
BOOST_CHECK_THROW(v1["foo"], toml::type_error);
}
}
BOOST_AUTO_TEST_CASE(test_value_map_methods)
{
{
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
BOOST_TEST(v1.count("foo") == 1u);
BOOST_TEST(v1.count("bar") == 1u);
BOOST_TEST(v1.count("baz") == 1u);
BOOST_TEST(v1.count("qux") == 0u);
BOOST_TEST( v1.contains("foo"));
BOOST_TEST( v1.contains("bar"));
BOOST_TEST( v1.contains("baz"));
BOOST_TEST(!v1.contains("qux"));
BOOST_TEST(v1.size() == 3);
v1["qux"] = 54;
BOOST_TEST(v1.count("qux") == 1u);
BOOST_TEST(v1.contains("qux"));
BOOST_TEST(v1.size() == 4);
}
{
toml::value v1(42);
BOOST_CHECK_THROW(v1.size() , toml::type_error);
BOOST_CHECK_THROW(v1.count("k") , toml::type_error);
BOOST_CHECK_THROW(v1.contains("k"), toml::type_error);
}
}
BOOST_AUTO_TEST_CASE(test_value_vector_methods)
{
{
toml::value v1{1, 2, 3, 4, 5};
BOOST_TEST(v1.size() == 5);
v1.push_back(6);
BOOST_TEST(v1.size() == 6);
v1.emplace_back(6);
BOOST_TEST(v1.size() == 7);
}
{
toml::value v1(42);
BOOST_CHECK_THROW(v1.size(), toml::type_error);
BOOST_CHECK_THROW(v1.push_back(1), toml::type_error);
BOOST_CHECK_THROW(v1.emplace_back(1), toml::type_error);
}
}

View File

@@ -1,12 +0,0 @@
#include <windows.h>
#include <toml.hpp>
#include <iostream>
int main()
{
using namespace toml::literals::toml_literals;
const auto data = R"(windows = "defines min and max as a macro")"_toml;
std::cout << toml::find<std::string>(data, "windows") << std::endl;
return 0;
}

View File

@@ -1,23 +0,0 @@
#ifndef BOOST_TEST_MODULE
# error "Please #define BOOST_TEST_MODULE before you #include <unit_test.hpp>"
#endif
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
# include <boost/test/unit_test.hpp>
#else
# include <boost/test/included/unit_test.hpp>
#endif
#include <cstdlib>
#include <string>
static inline auto testinput(const std::string& basename) -> std::string
{
const auto this_or_that = [](const char *const s, const char *const t) { return s ? s : t; };
std::string directory = this_or_that(std::getenv("TOMLDIR"), "toml");
if (!directory.empty() && directory.back() != '/')
{
directory.push_back('/');
}
return directory.append("tests/").append(basename);
}

View File

@@ -25,14 +25,18 @@
#ifndef TOML_FOR_MODERN_CPP
#define TOML_FOR_MODERN_CPP
#define TOML11_VERSION_MAJOR 3
#define TOML11_VERSION_MINOR 8
#define TOML11_VERSION_PATCH 0
#ifndef __cplusplus
# error "__cplusplus is not defined"
#endif
#if __cplusplus < 201103L && _MSC_VER < 1900
# error "toml11 requires C++11 or later."
#endif
#include "toml/parser.hpp"
#include "toml/literal.hpp"
#include "toml/serializer.hpp"
#include "toml/get.hpp"
#include "toml/macros.hpp"
#include "toml/find.hpp"
#endif// TOML_FOR_MODERN_CPP

View File

@@ -1,109 +0,0 @@
#ifndef TOML11_COLOR_HPP
#define TOML11_COLOR_HPP
#include <cstdint>
#include <ostream>
#ifdef TOML11_COLORIZE_ERROR_MESSAGE
#define TOML11_ERROR_MESSAGE_COLORIZED true
#else
#define TOML11_ERROR_MESSAGE_COLORIZED false
#endif
namespace toml
{
// put ANSI escape sequence to ostream
namespace color_ansi
{
namespace detail
{
inline int colorize_index()
{
static const int index = std::ios_base::xalloc();
return index;
}
// Control color mode globally
class color_mode
{
public:
inline void enable()
{
should_color_ = true;
}
inline void disable()
{
should_color_ = false;
}
inline bool should_color() const
{
return should_color_;
}
static color_mode& status()
{
static color_mode status_;
return status_;
}
private:
bool should_color_ = false;
};
} // detail
inline std::ostream& colorize(std::ostream& os)
{
// by default, it is zero.
os.iword(detail::colorize_index()) = 1;
return os;
}
inline std::ostream& nocolorize(std::ostream& os)
{
os.iword(detail::colorize_index()) = 0;
return os;
}
inline std::ostream& reset (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[00m";} return os;}
inline std::ostream& bold (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[01m";} return os;}
inline std::ostream& grey (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[30m";} return os;}
inline std::ostream& red (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[31m";} return os;}
inline std::ostream& green (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[32m";} return os;}
inline std::ostream& yellow (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[33m";} return os;}
inline std::ostream& blue (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[34m";} return os;}
inline std::ostream& magenta(std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[35m";} return os;}
inline std::ostream& cyan (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
inline std::ostream& white (std::ostream& os)
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
inline void enable()
{
return detail::color_mode::status().enable();
}
inline void disable()
{
return detail::color_mode::status().disable();
}
inline bool should_color()
{
return detail::color_mode::status().should_color();
}
} // color_ansi
// ANSI escape sequence is the only and default colorization method currently
namespace color = color_ansi;
} // toml
#endif// TOML11_COLOR_HPP

View File

@@ -2,20 +2,18 @@
// Distributed under the MIT License.
#ifndef TOML11_COMBINATOR_HPP
#define TOML11_COMBINATOR_HPP
#include <cassert>
#include <cctype>
#include <cstdio>
#include <array>
#include <iomanip>
#include "traits.hpp"
#include "result.hpp"
#include "utility.hpp"
#include "region.hpp"
#include <type_traits>
#include <iterator>
#include <limits>
#include <type_traits>
#include "region.hpp"
#include "result.hpp"
#include "traits.hpp"
#include "utility.hpp"
#include <array>
#include <iomanip>
#include <cstdio>
#include <cassert>
#include <cctype>
// they scans characters and returns region if it matches to the condition.
// when they fail, it does not change the location.
@@ -29,7 +27,7 @@ namespace detail
// to output character as an error message.
inline std::string show_char(const char c)
{
// It suppresses an error that occurs only in Debug mode of MSVC++ on Windows.
// It supress an error that occurs only in Debug mode of MSVC++ on Windows.
// I'm not completely sure but they check the value of char to be in the
// range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
// has negative value (if char has sign). So here it re-interprets c as
@@ -47,7 +45,6 @@ inline std::string show_char(const char c)
buf.fill('\0');
const auto r = std::snprintf(
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
(void) r; // Unused variable warning
assert(r == static_cast<int>(buf.size()) - 1);
return std::string(buf.data());
}
@@ -58,9 +55,13 @@ struct character
{
static constexpr char target = C;
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
@@ -71,7 +72,7 @@ struct character
}
loc.advance(); // update location
return ok(region(loc, first, loc.iter()));
return ok(region<Cont>(loc, first, loc.iter()));
}
};
template<char C>
@@ -87,9 +88,13 @@ struct in_range
static constexpr char upper = Up;
static constexpr char lower = Low;
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
@@ -100,7 +105,7 @@ struct in_range
}
loc.advance();
return ok(region(loc, first, loc.iter()));
return ok(region<Cont>(loc, first, loc.iter()));
}
};
template<char L, char U> constexpr char in_range<L, U>::upper;
@@ -111,9 +116,13 @@ template<char L, char U> constexpr char in_range<L, U>::lower;
template<typename Combinator>
struct exclude
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return none();}
auto first = loc.iter();
@@ -124,7 +133,7 @@ struct exclude
return none();
}
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
return ok(region(loc, first, loc.iter()));
return ok(region<Cont>(loc, first, loc.iter()));
}
};
@@ -132,15 +141,19 @@ struct exclude
template<typename Combinator>
struct maybe
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
const auto rslt = Combinator::invoke(loc);
if(rslt.is_ok())
{
return rslt;
}
return ok(region(loc));
return ok(region<Cont>(loc));
}
};
@@ -150,11 +163,15 @@ struct sequence;
template<typename Head, typename ... Tail>
struct sequence<Head, Tail...>
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
const auto first = loc.iter();
auto rslt = Head::invoke(loc);
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.reset(first);
@@ -164,9 +181,9 @@ struct sequence<Head, Tail...>
}
// called from the above function only, recursively.
template<typename Iterator>
static result<region, none_t>
invoke(location& loc, region reg, Iterator first)
template<typename Cont, typename Iterator>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
@@ -183,9 +200,9 @@ template<typename Head>
struct sequence<Head>
{
// would be called from sequence<T ...>::invoke only.
template<typename Iterator>
static result<region, none_t>
invoke(location& loc, region reg, Iterator first)
template<typename Cont, typename Iterator>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
@@ -204,9 +221,13 @@ struct either;
template<typename Head, typename ... Tail>
struct either<Head, Tail...>
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
const auto rslt = Head::invoke(loc);
if(rslt.is_ok()) {return rslt;}
return either<Tail...>::invoke(loc);
@@ -215,9 +236,12 @@ struct either<Head, Tail...>
template<typename Head>
struct either<Head>
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
return Head::invoke(loc);
}
};
@@ -232,10 +256,11 @@ struct unlimited{};
template<typename T, std::size_t N>
struct repeat<T, exactly<N>>
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region retval(loc);
region<Cont> retval(loc);
const auto first = loc.iter();
for(std::size_t i=0; i<N; ++i)
{
@@ -254,10 +279,11 @@ struct repeat<T, exactly<N>>
template<typename T, std::size_t N>
struct repeat<T, at_least<N>>
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region retval(loc);
region<Cont> retval(loc);
const auto first = loc.iter();
for(std::size_t i=0; i<N; ++i)
@@ -285,10 +311,11 @@ struct repeat<T, at_least<N>>
template<typename T>
struct repeat<T, unlimited>
{
static result<region, none_t>
invoke(location& loc)
template<typename Cont>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region retval(loc);
region<Cont> retval(loc);
while(true)
{
auto rslt = T::invoke(loc);

View File

@@ -2,19 +2,12 @@
// Distributed under the MIT License.
#ifndef TOML11_COMMENTS_HPP
#define TOML11_COMMENTS_HPP
#include <initializer_list>
#include <iterator>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <iterator>
#include <initializer_list>
#include <vector>
#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
#else
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
#endif
#include <string>
// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
// Those two are a container that have the same interface as `std::vector<std::string>`
@@ -88,54 +81,6 @@ struct preserve_comments
void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}
void assign(size_type n, const std::string& val) {comments.assign(n, val);}
// Related to the issue #97.
//
// It is known that `std::vector::insert` and `std::vector::erase` in
// the standard library implementation included in GCC 4.8.5 takes
// `std::vector::iterator` instead of `std::vector::const_iterator`.
// Because of the const-correctness, we cannot convert a `const_iterator` to
// an `iterator`. It causes compilation error in GCC 4.8.5.
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
# define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
# endif
#endif
#ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
iterator insert(iterator p, const std::string& x)
{
return comments.insert(p, x);
}
iterator insert(iterator p, std::string&& x)
{
return comments.insert(p, std::move(x));
}
void insert(iterator p, size_type n, const std::string& x)
{
return comments.insert(p, n, x);
}
template<typename InputIterator>
void insert(iterator p, InputIterator first, InputIterator last)
{
return comments.insert(p, first, last);
}
void insert(iterator p, std::initializer_list<std::string> ini)
{
return comments.insert(p, ini);
}
template<typename ... Ts>
iterator emplace(iterator p, Ts&& ... args)
{
return comments.emplace(p, std::forward<Ts>(args)...);
}
iterator erase(iterator pos) {return comments.erase(pos);}
iterator erase(iterator first, iterator last)
{
return comments.erase(first, last);
}
#else
iterator insert(const_iterator p, const std::string& x)
{
return comments.insert(p, x);
@@ -169,7 +114,6 @@ struct preserve_comments
{
return comments.erase(first, last);
}
#endif
void swap(preserve_comments& other) {comments.swap(other.comments);}
@@ -346,7 +290,7 @@ operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::differ
//
// Why this is chose as the default type is because the last version (2.x.y)
// does not contain any comments in a value. To minimize the impact on the
// efficiency, this is chosen as a default.
// efficiency, this is choosed as a default.
//
// To reduce the memory footprint, later we can try empty base optimization (EBO).
struct discard_comments
@@ -425,14 +369,14 @@ struct discard_comments
// empty, so accessing through operator[], front/back, data causes address
// error.
reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}
const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}
reference operator[](const size_type) noexcept {return *data();}
const_reference operator[](const size_type) const noexcept {return *data();}
reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
reference front() noexcept {never_call("toml::discard_comment::front");}
const_reference front() const noexcept {never_call("toml::discard_comment::front");}
reference back() noexcept {never_call("toml::discard_comment::back");}
const_reference back() const noexcept {never_call("toml::discard_comment::back");}
reference front() noexcept {return *data();}
const_reference front() const noexcept {return *data();}
reference back() noexcept {return *data();}
const_reference back() const noexcept {return *data();}
pointer data() noexcept {return nullptr;}
const_pointer data() const noexcept {return nullptr;}
@@ -450,18 +394,6 @@ struct discard_comments
const_reverse_iterator rend() const noexcept {return const_iterator{};}
const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
const_reverse_iterator crend() const noexcept {return const_iterator{};}
private:
[[noreturn]] static void never_call(const char *const this_function)
{
#ifdef __has_builtin
# if __has_builtin(__builtin_unreachable)
__builtin_unreachable();
# endif
#endif
throw std::logic_error{this_function};
}
};
inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}

View File

@@ -2,16 +2,15 @@
// Distributed under the MIT License.
#ifndef TOML11_DATETIME_HPP
#define TOML11_DATETIME_HPP
#include <chrono>
#include <tuple>
#include <array>
#include <ostream>
#include <iomanip>
#include <cstdint>
#include <cstdlib>
#include <ctime>
#include <array>
#include <chrono>
#include <iomanip>
#include <ostream>
#include <tuple>
namespace toml
{
@@ -21,22 +20,7 @@ namespace toml
namespace detail
{
// TODO: find more sophisticated way to handle this
#if defined(_MSC_VER)
inline std::tm localtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::localtime_s(&dst, src);
if (result) { throw std::runtime_error("localtime_s failed."); }
return dst;
}
inline std::tm gmtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::gmtime_s(&dst, src);
if (result) { throw std::runtime_error("gmtime_s failed."); }
return dst;
}
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
inline std::tm localtime_s(const std::time_t* src)
{
std::tm dst;
@@ -44,26 +28,21 @@ inline std::tm localtime_s(const std::time_t* src)
if (!result) { throw std::runtime_error("localtime_r failed."); }
return dst;
}
inline std::tm gmtime_s(const std::time_t* src)
#elif _MSC_VER
inline std::tm localtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::gmtime_r(src, &dst);
if (!result) { throw std::runtime_error("gmtime_r failed."); }
const auto result = ::localtime_s(&dst, src);
if (result) { throw std::runtime_error("localtime_s failed."); }
return dst;
}
#else // fallback. not threadsafe
#else
inline std::tm localtime_s(const std::time_t* src)
{
const auto result = std::localtime(src);
if (!result) { throw std::runtime_error("localtime failed."); }
return *result;
}
inline std::tm gmtime_s(const std::time_t* src)
{
const auto result = std::gmtime(src);
if (!result) { throw std::runtime_error("gmtime failed."); }
return *result;
}
#endif
} // detail
@@ -85,9 +64,9 @@ enum class month_t : std::uint8_t
struct local_date
{
std::int16_t year{}; // A.D. (like, 2018)
std::uint8_t month{}; // [0, 11]
std::uint8_t day{}; // [1, 31]
std::int16_t year; // A.D. (like, 2018)
std::uint8_t month; // [0, 11]
std::uint8_t day; // [1, 31]
local_date(int y, month_t m, int d)
: year (static_cast<std::int16_t>(y)),
@@ -174,19 +153,19 @@ std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
{
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ) ;
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month + 1) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day );
return os;
}
struct local_time
{
std::uint8_t hour{}; // [0, 23]
std::uint8_t minute{}; // [0, 59]
std::uint8_t second{}; // [0, 60]
std::uint16_t millisecond{}; // [0, 999]
std::uint16_t microsecond{}; // [0, 999]
std::uint16_t nanosecond{}; // [0, 999]
std::uint8_t hour; // [0, 23]
std::uint8_t minute; // [0, 59]
std::uint8_t second; // [0, 60]
std::uint16_t millisecond; // [0, 999]
std::uint16_t microsecond; // [0, 999]
std::uint16_t nanosecond; // [0, 999]
local_time(int h, int m, int s,
int ms = 0, int us = 0, int ns = 0)
@@ -297,8 +276,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_time& time)
struct time_offset
{
std::int8_t hour{}; // [-12, 12]
std::int8_t minute{}; // [-59, 59]
std::int8_t hour; // [-12, 12]
std::int8_t minute; // [-59, 59]
time_offset(int h, int m)
: hour (static_cast<std::int8_t>(h)),
@@ -364,8 +343,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
struct local_datetime
{
local_date date{};
local_time time{};
local_date date;
local_time time;
local_datetime(local_date d, local_time t): date(d), time(t) {}
@@ -399,31 +378,10 @@ struct local_datetime
{
using internal_duration =
typename std::chrono::system_clock::time_point::duration;
// Normally DST begins at A.M. 3 or 4. If we re-use conversion operator
// of local_date and local_time independently, the conversion fails if
// it is the day when DST begins or ends. Since local_date considers the
// time is 00:00 A.M. and local_time does not consider DST because it
// does not have any date information. We need to consider both date and
// time information at the same time to convert it correctly.
std::tm t;
t.tm_sec = static_cast<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(this->date.year) - 1900;
t.tm_wday = 0; // the value will be ignored
t.tm_yday = 0; // the value will be ignored
t.tm_isdst = -1;
// std::mktime returns date as local time zone. no conversion needed
auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t));
auto dt = std::chrono::system_clock::time_point(this->date);
dt += std::chrono::duration_cast<internal_duration>(
std::chrono::milliseconds(this->time.millisecond) +
std::chrono::microseconds(this->time.microsecond) +
std::chrono::nanoseconds (this->time.nanosecond));
std::chrono::nanoseconds(this->time));
return dt;
}
@@ -478,9 +436,9 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_datetime& dt)
struct offset_datetime
{
local_date date{};
local_time time{};
time_offset offset{};
local_date date;
local_time time;
time_offset offset;
offset_datetime(local_date d, local_time t, time_offset o)
: date(d), time(t), offset(o)
@@ -489,71 +447,40 @@ struct offset_datetime
: date(dt.date), time(dt.time), offset(o)
{}
explicit offset_datetime(const local_datetime& ld)
: date(ld.date), time(ld.time), offset(get_local_offset(nullptr))
// use the current local timezone offset
: date(ld.date), time(ld.time), offset(get_local_offset())
{}
explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
: offset(0, 0) // use gmtime
{
const auto timet = std::chrono::system_clock::to_time_t(tp);
const auto tm = detail::gmtime_s(&timet);
this->date = local_date(tm);
this->time = local_time(tm);
}
: offset_datetime(local_datetime(tp))
{}
explicit offset_datetime(const std::time_t& t)
: offset(0, 0) // use gmtime
{
const auto tm = detail::gmtime_s(&t);
this->date = local_date(tm);
this->time = local_time(tm);
}
: offset_datetime(local_datetime(t))
{}
explicit offset_datetime(const std::tm& t)
: offset(0, 0) // assume gmtime
{
this->date = local_date(t);
this->time = local_time(t);
}
: offset_datetime(local_datetime(t))
{}
operator std::chrono::system_clock::time_point() const
{
// get date-time
using internal_duration =
typename std::chrono::system_clock::time_point::duration;
std::chrono::system_clock::time_point tp =
std::chrono::system_clock::time_point(this->date) +
std::chrono::duration_cast<internal_duration>(
std::chrono::nanoseconds(this->time));
// first, convert it to local date-time information in the same way as
// local_datetime does. later we will use time_t to adjust time offset.
std::tm t;
t.tm_sec = static_cast<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(this->date.year) - 1900;
t.tm_wday = 0; // the value will be ignored
t.tm_yday = 0; // the value will be ignored
t.tm_isdst = -1;
const std::time_t tp_loc = std::mktime(std::addressof(t));
auto tp = std::chrono::system_clock::from_time_t(tp_loc);
tp += std::chrono::duration_cast<internal_duration>(
std::chrono::milliseconds(this->time.millisecond) +
std::chrono::microseconds(this->time.microsecond) +
std::chrono::nanoseconds (this->time.nanosecond));
// Since mktime uses local time zone, it should be corrected.
// `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if
// we are in `+09:00` timezone. To represent `12:00:00Z` there, we need
// to add `+09:00` to `03:00:00Z`.
// Here, it uses the time_t converted from date-time info to handle
// daylight saving time.
const auto ofs = get_local_offset(std::addressof(tp_loc));
// get date-time in UTC. let's say we are in +09:00 (JPN).
// writing 12:00:00 in +09:00 means 03:00:00Z. to represent
// 12:00:00Z, first we need to add +09:00.
const auto ofs = get_local_offset();
tp += std::chrono::hours (ofs.hour);
tp += std::chrono::minutes(ofs.minute);
// We got `12:00:00Z` by correcting local timezone applied by mktime.
// Then we will apply the offset. Let's say `12:00:00-08:00` is given.
// And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.
// So we need to subtract the offset.
// here, tp represents 12:00:00 in UTC but we have offset information.
// we need to subtract it. For example, let's say the input is
// 12:00:00-08:00. now we have tp = 12:00:00Z as a result of the above
// conversion. But the actual time we need to return is 20:00:00Z
// because of -08:00.
tp -= std::chrono::minutes(this->offset);
return tp;
}
@@ -573,10 +500,11 @@ struct offset_datetime
private:
static time_offset get_local_offset(const std::time_t* tp)
static time_offset get_local_offset()
{
// get local timezone with the same date-time information as mktime
const auto t = detail::localtime_s(tp);
// get current timezone
const auto tmp1 = std::time(nullptr);
const auto t = detail::localtime_s(&tmp1);
std::array<char, 6> buf;
const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0

View File

@@ -2,98 +2,24 @@
// Distributed under the MIT License.
#ifndef TOML11_EXCEPTION_HPP
#define TOML11_EXCEPTION_HPP
#include <array>
#include <string>
#include <stdexcept>
#include <cstring>
#include "source_location.hpp"
#include <string>
namespace toml
{
namespace detail
{
inline std::string str_error(int errnum)
{
// C++ standard strerror is not thread-safe.
// C11 provides thread-safe version of this function, `strerror_s`, but it
// is not available in C++.
// To avoid using std::strerror, we need to use platform-specific functions.
// If none of the conditions are met, it calls std::strerror as a fallback.
#ifdef _MSC_VER // MSVC
constexpr std::size_t bufsize = 256;
std::array<char, bufsize> buf;
buf.fill('\0');
const auto result = strerror_s(buf.data(), bufsize, errnum);
if(result != 0)
{
return std::string("strerror_s failed");
}
else
{
return std::string(buf.data());
}
#elif defined(_GNU_SOURCE) && !(defined(__DARWIN_C_LEVEL) && __DARWIN_C_LEVEL >= 200112L )
constexpr std::size_t bufsize = 256;
std::array<char, bufsize> buf;
buf.fill('\0');
const char* result = strerror_r(errnum, buf.data(), bufsize);
return std::string(result);
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || ( defined(__DARWIN_C_LEVEL) && __DARWIN_C_LEVEL >= 200112L ) // macOS
constexpr std::size_t bufsize = 256;
std::array<char, bufsize> buf;
buf.fill('\0');
const int result = strerror_r(errnum, buf.data(), bufsize);
if (result != 0)
{
return std::string("strerror_r failed");
}
else
{
return std::string(buf.data());
}
#else // fallback
return std::strerror(errnum);
#endif
}
} // detail
struct file_io_error : public std::runtime_error
{
public:
file_io_error(int errnum, const std::string& msg, const std::string& fname)
: std::runtime_error(msg + " \"" + fname + "\": " + detail::str_error(errnum)),
errno_(errnum)
{}
int get_errno() const noexcept {return errno_;}
private:
int errno_;
};
struct exception : public std::exception
{
public:
explicit exception(const source_location& loc): loc_(loc) {}
virtual ~exception() noexcept override = default;
virtual const char* what() const noexcept override {return "";}
virtual source_location const& location() const noexcept {return loc_;}
protected:
source_location loc_;
};
struct syntax_error : public toml::exception
{
public:
explicit syntax_error(const std::string& what_arg, const source_location& loc)
: exception(loc), what_(what_arg)
{}
explicit syntax_error(const std::string& what_arg) : what_(what_arg){}
explicit syntax_error(const char* what_arg) : what_(what_arg){}
virtual ~syntax_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();}
@@ -104,9 +30,8 @@ struct syntax_error : public toml::exception
struct type_error : public toml::exception
{
public:
explicit type_error(const std::string& what_arg, const source_location& loc)
: exception(loc), what_(what_arg)
{}
explicit type_error(const std::string& what_arg) : what_(what_arg){}
explicit type_error(const char* what_arg) : what_(what_arg){}
virtual ~type_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();}
@@ -117,12 +42,10 @@ struct type_error : public toml::exception
struct internal_error : public toml::exception
{
public:
explicit internal_error(const std::string& what_arg, const source_location& loc)
: exception(loc), what_(what_arg)
{}
explicit internal_error(const std::string& what_arg) : what_(what_arg){}
explicit internal_error(const char* what_arg) : what_(what_arg){}
virtual ~internal_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();}
protected:
std::string what_;
};

786
toml/find.hpp Normal file
View File

@@ -0,0 +1,786 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_FIND_HPP
#define TOML11_FIND_HPP
#include "get.hpp"
#include <numeric>
namespace toml
{
// ----------------------------------------------------------------------------
// these overloads do not require to set T. and returns value itself.
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
{
const auto& tab = v.template cast<value_t::table>();
if(tab.count(ky) == 0)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return tab.at(ky);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
{
auto& tab = v.template cast<value_t::table>();
if(tab.count(ky) == 0)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return tab.at(ky);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V>&& find(basic_value<C, M, V>&& v, const key& ky)
{
auto tab = std::move(v).as_table();
if(tab.count(ky) == 0)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return std::move(tab.at(ky));
}
// ----------------------------------------------------------------------------
// find<T>(value, key);
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
find(const basic_value<C, M, V>& v, const key& ky)
{
const auto& tab = v.as_table();
if(tab.count(ky) == 0)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return ::toml::get<T>(tab.at(ky));
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
find(basic_value<C, M, V>& v, const key& ky)
{
auto& tab = v.as_table();
if(tab.count(ky) == 0)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return ::toml::get<T>(tab.at(ky));
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
find(basic_value<C, M, V>&& v, const key& ky)
{
auto tab = std::move(v).as_table();
if(tab.count(ky) == 0)
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return ::toml::get<T>(std::move(tab.at(ky)));
}
// --------------------------------------------------------------------------
// toml::find(toml::value, toml::key, Ts&& ... keys)
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename ... Ts>
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
>::value, const basic_value<C, M, V>&>
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
{
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename ... Ts>
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
>::value, basic_value<C, M, V>&>
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
{
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename ... Ts>
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
>::value, basic_value<C, M, V>&&>
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
{
return ::toml::find(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename ... Ts>
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
>::value, decltype(get<T>(std::declval<const basic_value<C, M, V>&>()))>
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
{
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename ... Ts>
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
>::value, decltype(get<T>(std::declval<basic_value<C, M, V>&>()))>
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
{
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename ... Ts>
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
>::value, decltype(get<T>(std::declval<basic_value<C, M, V>&&>()))>
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
{
return ::toml::find<T>(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
}
// ===========================================================================
// find_or(value, key, fallback)
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V> const&
find_or(const basic_value<C, M, V>& v, const key& ky,
const basic_value<C, M, V>& opt)
{
if(!v.is_table()) {return opt;}
const auto& tab = v.as_table();
if(tab.count(ky) == 0) {return opt;}
return tab.at(ky);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V>&
find_or(basic_value<C, M, V>& v, const toml::key& ky, basic_value<C, M, V>& opt)
{
if(!v.is_table()) {return opt;}
auto& tab = v.as_table();
if(tab.count(ky) == 0) {return opt;}
return tab[ky];
}
template<typename C,
template<typename ...> class M, template<typename ...> class V>
basic_value<C, M, V>
find_or(basic_value<C, M, V>&& v, const toml::key& ky, basic_value<C, M, V>&& opt)
{
if(!v.is_table()) {return std::move(opt);}
auto tab = std::move(v).as_table();
if(tab.count(ky) == 0) {return std::move(opt);}
return std::move(tab[ky]);
}
// ---------------------------------------------------------------------------
// exact types (return type can be a reference)
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
{
if(!v.is_table()) {return opt;}
const auto& tab = v.as_table();
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), opt);
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&
find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
{
if(!v.is_table()) {return opt;}
auto& tab = v.as_table();
if(tab.count(ky) == 0) {return opt;}
return get_or(tab[ky], opt);
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&&
find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return std::forward<T>(opt);}
auto tab = std::move(v).as_table();
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return get_or(std::move(tab[ky]), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// std::string (return type can be a reference)
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<std::is_same<T, std::string>::value, std::string> const&
find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
{
if(!v.is_table()) {return opt;}
const auto& tab = v.as_table();
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), opt);
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
{
if(!v.is_table()) {return opt;}
auto& tab = v.as_table();
if(tab.count(ky) == 0) {return opt;}
return get_or(tab.at(ky), opt);
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<std::is_same<T, std::string>::value, std::string>
find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return std::forward<T>(opt);}
auto tab = std::move(v).as_table();
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return get_or(std::move(tab.at(ky)), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// string literal (deduced as std::string)
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
std::string>
find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return std::string(opt);}
const auto& tab = v.as_table();
if(tab.count(ky) == 0) {return std::string(opt);}
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ---------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
detail::enable_if_t<detail::conjunction<
// T is not an exact toml type
detail::negation<detail::is_exact_toml_type<
typename std::remove_cv<typename std::remove_reference<T>::type>::type,
basic_value<C, M, V>>>,
// T is not std::string
detail::negation<std::is_same<std::string,
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
// T is not a string literal
detail::negation<detail::is_string_literal<
typename std::remove_reference<T>::type>>
>::value, typename std::remove_cv<typename std::remove_reference<T>::type>::type>
find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
{
if(!v.is_table()) {return std::forward<T>(opt);}
const auto& tab = v.as_table();
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
return get_or(tab.at(ky), std::forward<T>(opt));
}
// ============================================================================
// expect
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
result<T, std::string> expect(const basic_value<C, M, V>& v) noexcept
{
try
{
return ok(get<T>(v));
}
catch(const std::exception& e)
{
return err(e.what());
}
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V>
result<T, std::string>
expect(const basic_value<C, M, V>& v, const toml::key& k) noexcept
{
try
{
return ok(find<T>(v, k));
}
catch(const std::exception& e)
{
return err(e.what());
}
}
template<typename T, typename Table>
detail::enable_if_t<detail::conjunction<
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>
>::value, result<T, std::string>>
expect(const Table& t, const toml::key& k,
std::string tablename = "unknown table") noexcept
{
try
{
return ok(find<T>(t, k, std::move(tablename)));
}
catch(const std::exception& e)
{
return err(e.what());
}
}
// ===========================================================================
// find_fuzzy
// ---------------------------------------------------------------------------
// default fuzzy matcher; levenstein distance (all cost is 1)
struct levenstein_matcher
{
levenstein_matcher(): tolerance(1) {}
levenstein_matcher(const std::uint32_t tol): tolerance(tol) {}
~levenstein_matcher() = default;
levenstein_matcher(levenstein_matcher const&) = default;
levenstein_matcher(levenstein_matcher &&) = default;
levenstein_matcher& operator=(levenstein_matcher const&) = default;
levenstein_matcher& operator=(levenstein_matcher &&) = default;
template<typename charT, typename traitsT, typename Alloc1, typename Alloc2>
bool operator()(const std::basic_string<charT, traitsT, Alloc1>& lhs,
const std::basic_string<charT, traitsT, Alloc2>& rhs) const
{
return this->distance(lhs, rhs) <= this->tolerance;
}
template<typename charT, typename traitsT, typename Alloc1, typename Alloc2>
std::uint32_t distance(
const std::basic_string<charT, traitsT, Alloc1>& lhs,
const std::basic_string<charT, traitsT, Alloc2>& rhs) const
{
// force `lhs.size() <= rhs.size()`
if(lhs.size() > rhs.size()) {return this->distance(rhs, lhs);}
std::vector<std::uint32_t> matrix(lhs.size() + 1u);
std::iota(matrix.begin(), matrix.end(), 0);
for(const charT r : rhs)
{
std::uint32_t prev_diag = matrix.front();
matrix.front() += 1;
for(std::size_t i=0; i<lhs.size(); ++i)
{
const charT l = lhs[i];
if(traitsT::eq(l, r))
{
std::swap(matrix[i+1], prev_diag);
}
else
{
const auto tmp = matrix[i+1];
matrix[i+1] = std::min(prev_diag, std::min(matrix[i], matrix[i+1])) + 1;
prev_diag = tmp;
}
}
}
return matrix.back();
}
private:
std::uint32_t tolerance;
};
// ---------------------------------------------------------------------------
// toml::find_fuzzy<T>(v, "tablename", FuzzyMatcher);
namespace detail
{
template<typename Iterator, typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher>
Iterator find_unique(
Iterator iter, const Iterator end, const basic_value<C, M, V>& v,
const toml::key& k, const FuzzyMatcher& match)
{
Iterator found = end;
for(; iter != end; ++iter)
{
if(match(iter->first, k))
{
if(found != end)
{
throw std::out_of_range(detail::format_underline(
concat_to_string("[error] key \"", k, "\" not found."),
{
{std::addressof(detail::get_region(v)),"in this table"},
{std::addressof(detail::get_region(found->second)),
"did you mean this here?"},
{std::addressof(detail::get_region(iter->second)),
"or this?"}
}));
}
found = iter;
}
}
return found;
}
} // detail
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher = levenstein_matcher>
auto find_fuzzy(const basic_value<C, M, V>& v, const key& ky,
const FuzzyMatcher match = levenstein_matcher(1))
-> decltype(find<T>(std::declval<const basic_value<C, M, V>&>(), ky))
{
try
{
return find<T>(v, ky);
}
catch(const std::out_of_range& oor)
{
const auto& t = v.as_table();
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
if(found != t.end())
{
return get<T>(found->second);
}
throw;
}
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher = levenstein_matcher>
auto find_fuzzy(basic_value<C, M, V>& v, const key& ky,
const FuzzyMatcher match = levenstein_matcher(1))
-> decltype(find<T>(std::declval<basic_value<C, M, V>&>(), ky))
{
try
{
return find<T>(v, ky);
}
catch(const std::out_of_range& oor)
{
auto& t = v.as_table();
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
if(found != t.end())
{
return get<T>(found->second);
}
throw;
}
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher = levenstein_matcher>
auto find_fuzzy(basic_value<C, M, V>&& v_, const key& ky,
const FuzzyMatcher match = levenstein_matcher(1))
-> decltype(find<T>(std::declval<basic_value<C, M, V>&&>(), ky))
{
basic_value<C, M, V> v = v_; // to re-use later, store it once
try
{
return std::move(find<T>(v, ky)); // pass lref, move later
}
catch(const std::out_of_range& oor)
{
auto& t = v.as_table(); // because v is used here
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
if(found != t.end())
{
return get<T>(std::move(found->second));
}
throw;
}
}
// ---------------------------------------------------------------------------
// no-template-argument case (by default, return toml::value).
// toml::find_fuzzy(v, "tablename", FuzzyMatcher);
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher = levenstein_matcher>
basic_value<C, M, V> const&
find_fuzzy(const basic_value<C, M, V>& v, const key& ky,
const FuzzyMatcher match = levenstein_matcher(1))
{
try
{
return find(v, ky);
}
catch(const std::out_of_range& oor)
{
const auto& t = v.as_table();
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
if(found != t.end())
{
return found->second;
}
throw;
}
}
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher = levenstein_matcher>
basic_value<C, M, V>&
find_fuzzy(basic_value<C, M, V>& v, const key& ky,
const FuzzyMatcher match = levenstein_matcher(1))
{
try
{
return find(v, ky);
}
catch(const std::out_of_range& oor)
{
auto& t = v.as_table();
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
if(found != t.end())
{
return found->second;
}
throw;
}
}
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher = levenstein_matcher>
basic_value<C, M, V>&&
find_fuzzy(basic_value<C, M, V>&& v_, const key& ky,
const FuzzyMatcher match = levenstein_matcher(1))
{
basic_value<C, M, V> v = v_; // to re-use later, store it once
try
{
return std::move(find(v, ky));
}
catch(const std::out_of_range& oor)
{
auto& t = v.as_table();
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
if(found != t.end())
{
return std::move(found->second);
}
throw;
}
}
// ===========================================================================
// find(v, k, matcher)
//
// when matcher is passed, check a key that matches exists or not. if it exists,
// suggest that in the error message
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher>
basic_value<C, M, V> const&
find(const basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
{
const auto& tab = v.template cast<value_t::table>();
if(tab.count(ky) == 0)
{
for(const auto& kv : tab)
{
if(match(kv.first, ky))
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found."), {
{std::addressof(detail::get_region(v)), "in this table"},
{std::addressof(detail::get_region(kv.second)),
"did you mean this?"}
}));
}
}
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return tab.at(ky);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher>
basic_value<C, M, V>&
find(basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
{
auto& tab = v.template cast<value_t::table>();
if(tab.count(ky) == 0)
{
for(const auto& kv : tab)
{
if(match(kv.first, ky))
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found."), {
{std::addressof(detail::get_region(v)), "in this table"},
{std::addressof(detail::get_region(kv.second)),
"did you mean this?"}
}));
}
}
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return tab.at(ky);
}
template<typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher>
basic_value<C, M, V>&&
find(basic_value<C, M, V>&& v, const key& ky, FuzzyMatcher match)
{
auto tab = std::move(v).as_table();
if(tab.count(ky) == 0)
{
for(const auto& kv : tab)
{
if(match(kv.first, ky))
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found."), {
{std::addressof(detail::get_region(v)), "in this table"},
{std::addressof(detail::get_region(kv.second)),
"did you mean this?"}
}));
}
}
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return std::move(tab.at(ky));
}
// ----------------------------------------------------------------------------
// find<T>(value, key, fuzzy_matcher);
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher>
detail::enable_if_t<
detail::negation<std::is_convertible<FuzzyMatcher, std::string>>::value,
decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))>
find(const basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
{
const auto& tab = v.as_table();
if(tab.count(ky) == 0)
{
for(const auto& kv : tab)
{
if(match(kv.first, ky))
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found."), {
{std::addressof(detail::get_region(v)), "in this table"},
{std::addressof(detail::get_region(kv.second)),
"did you mean this here?"}
}));
}
}
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return ::toml::get<T>(tab.at(ky));
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher>
detail::enable_if_t<
detail::negation<std::is_convertible<FuzzyMatcher, std::string>>::value,
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))>
find(basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
{
auto& tab = v.as_table();
if(tab.count(ky) == 0)
{
for(const auto& kv : tab)
{
if(match(kv.first, ky))
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found."), {
{std::addressof(detail::get_region(v)), "in this table"},
{std::addressof(detail::get_region(kv.second)),
"did you mean this here?"}
}));
}
}
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return ::toml::get<T>(tab.at(ky));
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename FuzzyMatcher>
detail::enable_if_t<
detail::negation<std::is_convertible<FuzzyMatcher, std::string>>::value,
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))>
find(basic_value<C, M, V>&& v, const key& ky, FuzzyMatcher match)
{
auto tab = v.as_table();
if(tab.count(ky) == 0)
{
for(const auto& kv : tab)
{
if(match(kv.first, ky))
{
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found."), {
{std::addressof(detail::get_region(v)), "in this table"},
{std::addressof(detail::get_region(kv.second)),
"did you mean this here?"}
}));
}
}
throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), {
{std::addressof(detail::get_region(v)), "in this table"}
}));
}
return ::toml::get<T>(std::move(tab.at(ky)));
}
} // toml
#endif// TOML11_FIND_HPP

View File

@@ -2,6 +2,7 @@
// Distributed under the MIT License.
#ifndef TOML11_FROM_HPP
#define TOML11_FROM_HPP
#include "traits.hpp"
namespace toml
{

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
// Distributed under the MIT License.
#ifndef TOML11_INTO_HPP
#define TOML11_INTO_HPP
#include "traits.hpp"
namespace toml
{

View File

@@ -2,11 +2,11 @@
// Distributed under the MIT License.
#ifndef TOML11_LEXER_HPP
#define TOML11_LEXER_HPP
#include "combinator.hpp"
#include <stdexcept>
#include <istream>
#include <sstream>
#include <stdexcept>
#include "combinator.hpp"
#include <fstream>
namespace toml
{
@@ -63,15 +63,12 @@ using lex_integer = either<lex_bin_int, lex_oct_int, lex_hex_int, lex_dec_int>;
using lex_inf = sequence<character<'i'>, character<'n'>, character<'f'>>;
using lex_nan = sequence<character<'n'>, character<'a'>, character<'n'>>;
using lex_special_float = sequence<maybe<lex_sign>, either<lex_inf, lex_nan>>;
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>, lex_dec_int>;
using lex_zero_prefixable_int = sequence<lex_digit, repeat<either<lex_digit,
sequence<lex_underscore, lex_digit>>, unlimited>>;
using lex_fractional_part = sequence<character<'.'>, lex_zero_prefixable_int>;
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>,
maybe<lex_sign>, lex_zero_prefixable_int>;
using lex_float = either<lex_special_float,
sequence<lex_dec_int, either<lex_exponent_part,
sequence<lex_fractional_part, maybe<lex_exponent_part>>>>>;
@@ -118,11 +115,10 @@ using lex_local_time = lex_partial_time;
// ===========================================================================
using lex_quotation_mark = character<'"'>;
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab) is allowed
in_range<0x0A, 0x1F>,
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab)
in_range<0x0a, 0x1F>, // is allowed
character<0x22>, character<0x5C>,
character<0x7F>>>;
using lex_escape = character<'\\'>;
using lex_escape_unicode_short = sequence<character<'u'>,
repeat<lex_hex_dig, exactly<4>>>;
@@ -132,9 +128,6 @@ using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
character<'b'>, character<'f'>,
character<'n'>, character<'r'>,
character<'t'>,
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
character<'e'>, // ESC (0x1B)
#endif
lex_escape_unicode_short,
lex_escape_unicode_long
>;
@@ -144,46 +137,11 @@ using lex_basic_string = sequence<lex_quotation_mark,
repeat<lex_basic_char, unlimited>,
lex_quotation_mark>;
// After toml post-v0.5.0, it is explicitly clarified how quotes in ml-strings
// are allowed to be used.
// After this, the following strings are *explicitly* allowed.
// - One or two `"`s in a multi-line basic string is allowed wherever it is.
// - Three consecutive `"`s in a multi-line basic string is considered as a delimiter.
// - One or two `"`s can appear just before or after the delimiter.
// ```toml
// str4 = """Here are two quotation marks: "". Simple enough."""
// str5 = """Here are three quotation marks: ""\"."""
// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
// str7 = """"This," she said, "is just a pointless statement.""""
// ```
// In the current implementation (v3.3.0), it is difficult to parse `str7` in
// the above example. It is difficult to recognize `"` at the end of string body
// collectly. It will be misunderstood as a `"""` delimiter and an additional,
// invalid `"`. Like this:
// ```console
// what(): [error] toml::parse_table: invalid line format
// --> hoge.toml
// |
// 13 | str7 = """"This," she said, "is just a pointless statement.""""
// | ^- expected newline, but got '"'.
// ```
// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
// split into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s.
// In parse_ml_basic_string() function, the trailing `"`s will be attached to
// the string body.
//
using lex_ml_basic_string_delim = repeat<lex_quotation_mark, exactly<3>>;
using lex_ml_basic_string_open = lex_ml_basic_string_delim;
using lex_ml_basic_string_close = sequence<
repeat<lex_quotation_mark, exactly<3>>,
maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
>;
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 is tab
in_range<0x0A, 0x1F>,
character<0x5C>, // backslash
character<0x7F>, // DEL
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09
in_range<0x0a, 0x1F>, // is tab
character<0x5C>,
character<0x7F>,
lex_ml_basic_string_delim>>;
using lex_ml_basic_escaped_newline = sequence<
@@ -194,39 +152,39 @@ using lex_ml_basic_char = either<lex_ml_basic_unescaped, lex_escaped>;
using lex_ml_basic_body = repeat<either<lex_ml_basic_char, lex_newline,
lex_ml_basic_escaped_newline>,
unlimited>;
using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
using lex_ml_basic_string = sequence<lex_ml_basic_string_delim,
lex_ml_basic_body,
lex_ml_basic_string_close>;
lex_ml_basic_string_delim>;
using lex_literal_char = exclude<either<in_range<0x00, 0x08>, in_range<0x0A, 0x1F>,
character<0x7F>, character<0x27>>>;
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
in_range<0x10, 0x19>, character<0x27>>>;
using lex_apostrophe = character<'\''>;
using lex_literal_string = sequence<lex_apostrophe,
repeat<lex_literal_char, unlimited>,
lex_apostrophe>;
// the same reason as above.
using lex_ml_literal_string_delim = repeat<lex_apostrophe, exactly<3>>;
using lex_ml_literal_string_open = lex_ml_literal_string_delim;
using lex_ml_literal_string_close = sequence<
repeat<lex_apostrophe, exactly<3>>,
maybe<lex_apostrophe>, maybe<lex_apostrophe>
>;
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
in_range<0x0A, 0x1F>,
in_range<0x10, 0x1F>,
character<0x7F>,
lex_ml_literal_string_delim>>;
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
unlimited>;
using lex_ml_literal_string = sequence<lex_ml_literal_string_open,
using lex_ml_literal_string = sequence<lex_ml_literal_string_delim,
lex_ml_literal_body,
lex_ml_literal_string_close>;
lex_ml_literal_string_delim>;
using lex_string = either<lex_ml_basic_string, lex_basic_string,
lex_ml_literal_string, lex_literal_string>;
// ===========================================================================
using lex_comment_start_symbol = character<'#'>;
using lex_non_eol = either<character<'\t'>, exclude<in_range<0x00, 0x19>>>;
using lex_comment = sequence<lex_comment_start_symbol,
repeat<lex_non_eol, unlimited>>;
using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
@@ -261,34 +219,6 @@ using lex_array_table = sequence<lex_array_table_open,
maybe<lex_ws>,
lex_array_table_close>;
using lex_utf8_1byte = in_range<0x00, 0x7F>;
using lex_utf8_2byte = sequence<
in_range<'\xC2', '\xDF'>,
in_range<'\x80', '\xBF'>
>;
using lex_utf8_3byte = sequence<either<
sequence<character<'\xE0'>, in_range<'\xA0', '\xBF'>>,
sequence<in_range<'\xE1', '\xEC'>, in_range<'\x80', '\xBF'>>,
sequence<character<'\xED'>, in_range<'\x80', '\x9F'>>,
sequence<in_range<'\xEE', '\xEF'>, in_range<'\x80', '\xBF'>>
>, in_range<'\x80', '\xBF'>>;
using lex_utf8_4byte = sequence<either<
sequence<character<'\xF0'>, in_range<'\x90', '\xBF'>>,
sequence<in_range<'\xF1', '\xF3'>, in_range<'\x80', '\xBF'>>,
sequence<character<'\xF4'>, in_range<'\x80', '\x8F'>>
>, in_range<'\x80', '\xBF'>, in_range<'\x80', '\xBF'>>;
using lex_utf8_code = either<
lex_utf8_1byte,
lex_utf8_2byte,
lex_utf8_3byte,
lex_utf8_4byte
>;
using lex_comment_start_symbol = character<'#'>;
using lex_non_eol_ascii = either<character<0x09>, in_range<0x20, 0x7E>>;
using lex_comment = sequence<lex_comment_start_symbol, repeat<either<
lex_non_eol_ascii, lex_utf8_2byte, lex_utf8_3byte, lex_utf8_4byte>, unlimited>>;
} // detail
} // toml
#endif // TOML_LEXER_HPP

View File

@@ -11,12 +11,12 @@ inline namespace literals
inline namespace toml_literals
{
// implementation
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
literal_internal_impl(::toml::detail::location loc)
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
{
using value_type = ::toml::basic_value<
TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
::toml::detail::location<std::vector<char>>
loc(/* filename = */ std::string("TOML literal encoded in a C++ code"),
/* contents = */ std::vector<char>(str, str + len));
// if there are some comments or empty lines, skip them.
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
::toml::detail::maybe<::toml::detail::lex_ws>,
@@ -53,7 +53,7 @@ literal_internal_impl(::toml::detail::location loc)
// If it is neither a table-key or a array-of-table-key, it may be a value.
if(!is_table_key && !is_aots_key)
{
if(auto data = ::toml::detail::parse_value<value_type>(loc, 0))
if(auto data = ::toml::detail::parse_value<::toml::value>(loc))
{
return data.unwrap();
}
@@ -70,43 +70,16 @@ literal_internal_impl(::toml::detail::location loc)
// It is a valid toml file.
// It should be parsed as if we parse a file with this content.
if(auto data = ::toml::detail::parse_toml_file<value_type>(loc))
if(auto data = ::toml::detail::parse_toml_file<::toml::value>(loc))
{
return data.unwrap();
}
else // none of them.
{
throw ::toml::syntax_error(data.unwrap_err(), source_location(loc));
throw ::toml::syntax_error(data.unwrap_err());
}
}
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
operator"" _toml(const char* str, std::size_t len)
{
::toml::detail::location loc(
std::string("TOML literal encoded in a C++ code"),
std::vector<char>(str, str + len));
// literal length does not include the null character at the end.
return literal_internal_impl(std::move(loc));
}
// value of __cplusplus in C++2a/20 mode is not fixed yet along compilers.
// So here we use the feature test macro for `char8_t` itself.
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
// value of u8"" literal has been changed from char to char8_t and char8_t is
// NOT compatible to char
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
operator"" _toml(const char8_t* str, std::size_t len)
{
::toml::detail::location loc(
std::string("TOML literal encoded in a C++ code"),
std::vector<char>(reinterpret_cast<const char*>(str),
reinterpret_cast<const char*>(str) + len));
return literal_internal_impl(std::move(loc));
}
#endif
} // toml_literals
} // literals
} // toml

View File

@@ -1,121 +0,0 @@
#ifndef TOML11_MACROS_HPP
#define TOML11_MACROS_HPP
#define TOML11_STRINGIZE_AUX(x) #x
#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x)
#define TOML11_CONCATENATE_AUX(x, y) x##y
#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y)
// ============================================================================
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
// ----------------------------------------------------------------------------
// TOML11_ARGS_SIZE
#define TOML11_INDEX_RSEQ() \
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#define TOML11_ARGS_SIZE_IMPL(\
ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, \
ARG11, ARG12, ARG13, ARG14, ARG15, ARG16, ARG17, ARG18, ARG19, ARG20, \
ARG21, ARG22, ARG23, ARG24, ARG25, ARG26, ARG27, ARG28, ARG29, ARG30, \
ARG31, ARG32, N, ...) N
#define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__)
#define TOML11_ARGS_SIZE(...) TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ())
// ----------------------------------------------------------------------------
// TOML11_FOR_EACH_VA_ARGS
#define TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, ARG1 ) FUNCTOR(ARG1)
#define TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__)
#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)
// ----------------------------------------------------------------------------
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
// use it in the following way.
// ```cpp
// namespace foo
// {
// struct Foo
// {
// std::string s;
// double d;
// int i;
// };
// } // foo
//
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
// ```
// And then you can use `toml::find<foo::Foo>(file, "foo");`
//
#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\
obj.VAR_NAME = toml::find<decltype(obj.VAR_NAME)>(v, TOML11_STRINGIZE(VAR_NAME));
#define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\
v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME;
#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
namespace toml { \
template<> \
struct from<NAME> \
{ \
template<typename C, template<typename ...> class T, \
template<typename ...> class A> \
static NAME from_toml(const basic_value<C, T, A>& v) \
{ \
NAME obj; \
TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
return obj; \
} \
}; \
template<> \
struct into<NAME> \
{ \
static value into_toml(const NAME& obj) \
{ \
::toml::value v = ::toml::table{}; \
TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \
return v; \
} \
}; \
} /* toml */
#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
#endif// TOML11_MACROS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
// Distributed under the MIT License.
#ifndef TOML11_REGION_HPP
#define TOML11_REGION_HPP
#include "exception.hpp"
#include <memory>
#include <vector>
#include <algorithm>
@@ -9,7 +10,6 @@
#include <iterator>
#include <iomanip>
#include <cassert>
#include "color.hpp"
namespace toml
{
@@ -41,7 +41,6 @@ struct region_base
region_base& operator=(region_base&& ) = default;
virtual bool is_ok() const noexcept {return false;}
virtual char front() const noexcept {return '\0';}
virtual std::string str() const {return std::string("unknown region");}
virtual std::string name() const {return std::string("unknown file");}
@@ -55,7 +54,7 @@ struct region_base
// number of characters in the line after the region
virtual std::size_t after() const noexcept {return 0;}
virtual std::vector<std::string> comments() const {return {};}
virtual std::vector<std::string> comments()const {return {};}
// ```toml
// # comment_before
// key = "value" # comment_inline
@@ -67,21 +66,22 @@ struct region_base
//
// it contains pointer to the file content and iterator that points the current
// location.
template<typename Container>
struct location final : public region_base
{
using const_iterator = typename std::vector<char>::const_iterator;
using difference_type = typename std::iterator_traits<const_iterator>::difference_type;
using source_ptr = std::shared_ptr<const std::vector<char>>;
using const_iterator = typename Container::const_iterator;
using difference_type = typename const_iterator::difference_type;
using source_ptr = std::shared_ptr<const Container>;
location(std::string source_name, std::vector<char> cont)
: source_(std::make_shared<std::vector<char>>(std::move(cont))),
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
{}
location(std::string source_name, const std::string& cont)
: source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
{}
static_assert(std::is_same<char, typename Container::value_type>::value,"");
static_assert(std::is_same<std::random_access_iterator_tag,
typename std::iterator_traits<const_iterator>::iterator_category>::value,
"container should be randomly accessible");
location(std::string name, Container cont)
: source_(std::make_shared<Container>(std::move(cont))), line_number_(1),
source_name_(std::move(name)), iter_(source_->cbegin())
{}
location(const location&) = default;
location(location&&) = default;
location& operator=(const location&) = default;
@@ -89,10 +89,9 @@ struct location final : public region_base
~location() = default;
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
char front() const noexcept override {return *iter_;}
// this const prohibits codes like `++(loc.iter())`.
std::add_const<const_iterator>::type iter() const noexcept {return iter_;}
const const_iterator iter() const noexcept {return iter_;}
const_iterator begin() const noexcept {return source_->cbegin();}
const_iterator end() const noexcept {return source_->cend();}
@@ -194,27 +193,33 @@ struct location final : public region_base
//
// it contains pointer to the file content and iterator that points the first
// and last location.
template<typename Container>
struct region final : public region_base
{
using const_iterator = typename std::vector<char>::const_iterator;
using source_ptr = std::shared_ptr<const std::vector<char>>;
using const_iterator = typename Container::const_iterator;
using source_ptr = std::shared_ptr<const Container>;
static_assert(std::is_same<char, typename Container::value_type>::value,"");
static_assert(std::is_same<std::random_access_iterator_tag,
typename std::iterator_traits<const_iterator>::iterator_category>::value,
"container should be randomly accessible");
// delete default constructor. source_ never be null.
region() = delete;
explicit region(const location& loc)
region(const location<Container>& loc)
: source_(loc.source()), source_name_(loc.name()),
first_(loc.iter()), last_(loc.iter())
{}
explicit region(location&& loc)
region(location<Container>&& loc)
: source_(loc.source()), source_name_(loc.name()),
first_(loc.iter()), last_(loc.iter())
{}
region(const location& loc, const_iterator f, const_iterator l)
region(const location<Container>& loc, const_iterator f, const_iterator l)
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
{}
region(location&& loc, const_iterator f, const_iterator l)
region(location<Container>&& loc, const_iterator f, const_iterator l)
: source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
{}
@@ -226,15 +231,16 @@ struct region final : public region_base
region& operator+=(const region& other)
{
// different regions cannot be concatenated
assert(this->source_ == other.source_ && this->last_ == other.first_);
if(this->begin() != other.begin() || this->end() != other.end() ||
this->last_ != other.first_)
{
throw internal_error("invalid region concatenation");
}
this->last_ = other.last_;
return *this;
}
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
char front() const noexcept override {return *first_;}
std::string str() const override {return make_string(first_, last_);}
std::string line() const override
@@ -342,9 +348,9 @@ struct region final : public region_base
}))
{
// unwrap the first '#' by std::next.
auto s = make_string(std::next(comment_found), iter);
if(!s.empty() && s.back() == '\r') {s.pop_back();}
com.push_back(std::move(s));
auto str = make_string(std::next(comment_found), iter);
if(str.back() == '\r') {str.pop_back();}
com.push_back(std::move(str));
}
else
{
@@ -395,9 +401,9 @@ struct region final : public region_base
}))
{
// unwrap the first '#' by std::next.
auto s = make_string(std::next(comment_found), this->line_end());
if(!s.empty() && s.back() == '\r') {s.pop_back();}
com.push_back(std::move(s));
auto str = make_string(std::next(comment_found), this->line_end());
if(str.back() == '\r') {str.pop_back();}
com.push_back(std::move(str));
}
}
}
@@ -411,6 +417,78 @@ struct region final : public region_base
const_iterator first_, last_;
};
// to show a better error message.
inline std::string format_underline(const std::string& message,
const std::vector<std::pair<region_base const*, std::string>>& reg_com,
const std::vector<std::string>& helps = {})
{
assert(!reg_com.empty());
const auto line_num_width = static_cast<int>(std::max_element(
reg_com.begin(), reg_com.end(),
[](std::pair<region_base const*, std::string> const& lhs,
std::pair<region_base const*, std::string> const& rhs)
{
return lhs.first->line_num().size() < rhs.first->line_num().size();
}
)->first->line_num().size());
std::ostringstream retval;
retval << message << '\n';
for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter)
{
// if the filenames are the same, print "..."
if(iter != reg_com.begin() &&
std::prev(iter)->first->name() == iter->first->name())
{
retval << "\n ...\n";
}
else // if filename differs, print " --> filename.toml"
{
if(iter != reg_com.begin()) {retval << '\n';}
retval << " --> " << iter->first->name() << '\n';
}
const region_base* const reg = iter->first;
const std::string& comment = iter->second;
retval << ' ' << std::setw(line_num_width) << reg->line_num();
retval << " | " << reg->line() << '\n';
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
retval << " | " << make_string(reg->before(), ' ');
if(reg->size() == 1)
{
// invalid
// ^------
retval << '^';
retval << make_string(reg->after(), '-');
}
else
{
// invalid
// ~~~~~~~
const auto underline_len = std::min(reg->size(), reg->line().size());
retval << make_string(underline_len, '~');
}
retval << ' ';
retval << comment;
}
if(!helps.empty())
{
retval << '\n';
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
retval << " | ";
for(const auto help : helps)
{
retval << "\nHint: ";
retval << help;
}
}
return retval.str();
}
} // detail
} // toml
#endif// TOML11_REGION_H

View File

@@ -2,21 +2,10 @@
// Distributed under the MIT License.
#ifndef TOML11_SERIALIZER_HPP
#define TOML11_SERIALIZER_HPP
#include <cmath>
#include <cstdio>
#include <limits>
#if defined(_WIN32)
#include <locale.h>
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <xlocale.h>
#elif defined(__linux__)
#include <locale.h>
#endif
#include "lexer.hpp"
#include "value.hpp"
#include "lexer.hpp"
#include <limits>
#include <cstdio>
namespace toml
{
@@ -33,82 +22,39 @@ namespace toml
// Since toml restricts characters available in a bare key, generally a string
// should be escaped. But checking whether a string needs to be surrounded by
// a `"` and escaping some special character is boring.
template<typename charT, typename traits, typename Alloc>
std::basic_string<charT, traits, Alloc>
format_key(const std::basic_string<charT, traits, Alloc>& k)
inline std::string format_key(const toml::key& key)
{
if(k.empty())
{
return std::string("\"\"");
}
// check the key can be a bare (unquoted) key
detail::location loc(k, std::vector<char>(k.begin(), k.end()));
detail::location<toml::key> loc(key, key);
detail::lex_unquoted_key::invoke(loc);
if(loc.iter() == loc.end())
{
return k; // all the tokens are consumed. the key is unquoted-key.
return key; // all the tokens are consumed. the key is unquoted-key.
}
//if it includes special characters, then format it in a "quoted" key.
std::basic_string<charT, traits, Alloc> serialized("\"");
for(const char c : k)
std::string token("\"");
for(const char c : key)
{
switch(c)
{
case '\\': {serialized += "\\\\"; break;}
case '\"': {serialized += "\\\""; break;}
case '\b': {serialized += "\\b"; break;}
case '\t': {serialized += "\\t"; break;}
case '\f': {serialized += "\\f"; break;}
case '\n': {serialized += "\\n"; break;}
case '\r': {serialized += "\\r"; break;}
default: {
if (c >= 0x00 && c < 0x20)
{
std::array<char, 7> buf;
std::snprintf(buf.data(), buf.size(), "\\u00%02x", static_cast<int>(c));
serialized += buf.data();
}
else
{
serialized += c;
}
break;
case '\\': {token += "\\\\"; break;}
case '\"': {token += "\\\""; break;}
case '\b': {token += "\\b"; break;}
case '\t': {token += "\\t"; break;}
case '\f': {token += "\\f"; break;}
case '\n': {token += "\\n"; break;}
case '\r': {token += "\\r"; break;}
default : {token += c; break;}
}
}
}
serialized += "\"";
return serialized;
token += "\"";
return token;
}
template<typename charT, typename traits, typename Alloc>
std::basic_string<charT, traits, Alloc>
format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
{
if(keys.empty())
{
return std::string("\"\"");
}
std::basic_string<charT, traits, Alloc> serialized;
for(const auto& ky : keys)
{
serialized += format_key(ky);
serialized += charT('.');
}
serialized.pop_back(); // remove the last dot '.'
return serialized;
}
template<typename Value>
template<typename Comment,
template<typename ...> class Table,
template<typename ...> class Array>
struct serializer
{
static_assert(detail::is_basic_value<Value>::value,
"toml::serializer is for toml::value and its variants, "
"toml::basic_value<...>.");
using value_type = Value;
using value_type = basic_value<Comment, Table, Array>;
using key_type = typename value_type::key_type ;
using comment_type = typename value_type::comment_type ;
using boolean_type = typename value_type::boolean_type ;
@@ -126,10 +72,8 @@ struct serializer
const int float_prec = std::numeric_limits<toml::floating>::max_digits10,
const bool can_be_inlined = false,
const bool no_comment = false,
std::vector<toml::key> ks = {},
const bool value_has_comment = false)
std::vector<toml::key> ks = {})
: can_be_inlined_(can_be_inlined), no_comment_(no_comment),
value_has_comment_(value_has_comment && !no_comment),
float_prec_(float_prec), width_(w), keys_(std::move(ks))
{}
~serializer() = default;
@@ -140,93 +84,18 @@ struct serializer
}
std::string operator()(const integer_type i) const
{
#if defined(_WIN32)
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
setlocale(LC_NUMERIC, "C");
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
locale_t original_locale(0);
if(c_locale != locale_t(0))
{
original_locale = uselocale(c_locale);
}
#endif
const auto str = std::to_string(i);
#if defined(_WIN32)
setlocale(LC_NUMERIC, original_locale.c_str());
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
if(original_locale != locale_t(0))
{
uselocale(original_locale);
}
#endif
return str;
return std::to_string(i);
}
std::string operator()(const floating_type f) const
{
if(std::isnan(f))
{
if(std::signbit(f))
{
return std::string("-nan");
}
else
{
return std::string("nan");
}
}
else if(!std::isfinite(f))
{
if(std::signbit(f))
{
return std::string("-inf");
}
else
{
return std::string("inf");
}
}
// set locale to "C".
// To make it thread-local, we use OS-specific features.
// If we set process-global locale, it can break other thread that also
// outputs something simultaneously.
#if defined(_WIN32)
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
setlocale(LC_NUMERIC, "C");
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
locale_t original_locale(0);
if(c_locale != locale_t(0))
{
original_locale = uselocale(c_locale);
}
#endif
const auto fmt = "%.*g";
const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
// +1 for null character(\0)
std::vector<char> buf(static_cast<std::size_t>(bsz + 1), '\0');
std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
// restore the original locale
#if defined(_WIN32)
setlocale(LC_NUMERIC, original_locale.c_str());
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
if(original_locale != locale_t(0))
{
uselocale(original_locale);
}
#endif
std::string token(buf.begin(), std::prev(buf.end()));
if(!token.empty() && token.back() == '.') // 1. => 1.0
if(token.back() == '.') // 1. => 1.0
{
token += '0';
}
@@ -243,6 +112,29 @@ struct serializer
{
// the resulting value does not have any float specific part!
token += ".0";
return token;
}
if(!has_exponent)
{
return token; // there is no exponent part. just return it.
}
// zero-prefix in an exponent is NOT allowed in TOML.
// remove it if it exists.
bool sign_exists = false;
std::size_t zero_prefix = 0;
for(auto iter = std::next(e), iend = token.cend(); iter != iend; ++iter)
{
if(*iter == '+' || *iter == '-'){sign_exists = true; continue;}
if(*iter == '0'){zero_prefix += 1;}
else {break;}
}
if(zero_prefix != 0)
{
const auto offset = std::distance(token.cbegin(), e) +
(sign_exists ? 2 : 1);
token.erase(static_cast<typename std::string::size_type>(offset),
zero_prefix);
}
return token;
}
@@ -250,24 +142,12 @@ struct serializer
{
if(s.kind == string_t::basic)
{
if((std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend()) &&
this->width_ != (std::numeric_limits<std::size_t>::max)())
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
{
// if linefeed or double-quote is contained,
// make it multiline basic string.
const auto escaped = this->escape_ml_basic_string(s.str);
std::string open("\"\"\"");
std::string close("\"\"\"");
if(escaped.find('\n') != std::string::npos ||
this->width_ < escaped.size() + 6)
{
// if the string body contains newline or is enough long,
// add newlines after and before delimiters.
open += "\n";
close = std::string("\\\n") + close;
}
return open + escaped + close;
// if linefeed is contained, make it multiline-string.
const std::string open("\"\"\"\n");
const std::string close("\\\n\"\"\"");
return open + this->escape_ml_basic_string(s.str) + close;
}
// no linefeed. try to make it oneline-string.
@@ -308,11 +188,7 @@ struct serializer
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
{
std::string open("'''");
if(this->width_ + 6 < s.str.size())
{
open += '\n'; // the first newline is ignored by TOML spec
}
const std::string open("'''\n");
const std::string close("'''");
return open + s.str + close;
}
@@ -351,18 +227,92 @@ struct serializer
std::string operator()(const array_type& v) const
{
if(!v.empty() && v.front().is_table())// v is an array of tables
{
// if it's not inlined, we need to add `[[table.key]]`.
// but if it can be inlined,
// ```
// table.key = [
// {...},
// # comment
// {...},
// ]
// ```
if(this->can_be_inlined_)
{
std::string token;
if(!keys_.empty())
{
token += this->serialize_key(keys_.back());
token += " = ";
}
bool failed = false;
token += "[\n";
for(const auto& item : v)
{
// if an element of the table has a comment, the table
// cannot be inlined.
if(this->has_comment_inside(item.as_table()))
{
failed = true;
break;
}
if(!no_comment_)
{
for(const auto& c : item.comments())
{
token += '#';
token += c;
token += '\n';
}
}
const auto t = this->make_inline_table(item.as_table());
if(t.size() + 1 > width_ || // +1 for the last comma {...},
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
{
failed = true;
break;
}
token += t;
token += ",\n";
}
if(!failed)
{
token += "]\n";
return token;
}
// if failed, serialize them as [[array.of.tables]].
}
std::string token;
for(const auto& item : v)
{
if(!no_comment_)
{
for(const auto& c : item.comments())
{
token += '#';
token += c;
token += '\n';
}
}
token += "[[";
token += this->serialize_dotted_key(keys_);
token += "]]\n";
token += this->make_multiline_table(item.as_table());
}
return token;
}
if(v.empty())
{
return std::string("[]");
}
if(this->is_array_of_tables(v))
{
return make_array_of_tables(v);
}
// not an array of tables. normal array.
// first, try to make it inline if none of the elements have a comment.
if( ! this->has_comment_inside(v))
if(!this->has_comment_inside(v))
{
const auto inl = this->make_inline_array(v);
if(inl.size() < this->width_ &&
@@ -383,7 +333,7 @@ struct serializer
token += "[\n";
for(const auto& item : v)
{
if( ! item.comments().empty() && !no_comment_)
if(!item.comments().empty() && !no_comment_)
{
// if comment exists, the element must be the only element in the line.
// e.g. the following is not allowed.
@@ -409,25 +359,15 @@ struct serializer
token += '\n';
}
token += toml::visit(*this, item);
if(!token.empty() && token.back() == '\n') {token.pop_back();}
if(token.back() == '\n') {token.pop_back();}
token += ",\n";
continue;
}
std::string next_elem;
if(item.is_table())
{
serializer ser(*this);
ser.can_be_inlined_ = true;
ser.width_ = (std::numeric_limits<std::size_t>::max)();
next_elem += toml::visit(ser, item);
}
else
{
next_elem += toml::visit(*this, item);
}
// comma before newline.
if(!next_elem.empty() && next_elem.back() == '\n') {next_elem.pop_back();}
if(next_elem.back() == '\n') {next_elem.pop_back();}
// if current line does not exceeds the width limit, continue.
if(current_line.size() + next_elem.size() + 1 < this->width_)
@@ -454,10 +394,7 @@ struct serializer
}
if(!current_line.empty())
{
if(!current_line.empty() && current_line.back() != '\n')
{
current_line += '\n';
}
if(current_line.back() != '\n') {current_line += '\n';}
token += current_line;
}
token += "]\n";
@@ -474,7 +411,7 @@ struct serializer
std::string token;
if(!this->keys_.empty())
{
token += format_key(this->keys_.back());
token += this->serialize_key(this->keys_.back());
token += " = ";
}
token += this->make_inline_table(v);
@@ -489,7 +426,7 @@ struct serializer
if(!keys_.empty())
{
token += '[';
token += format_keys(keys_);
token += this->serialize_dotted_key(keys_);
token += "]\n";
}
token += this->make_multiline_table(v);
@@ -498,6 +435,25 @@ struct serializer
private:
std::string serialize_key(const toml::key& key) const
{
return ::toml::format_key(key);
}
std::string serialize_dotted_key(const std::vector<toml::key>& keys) const
{
std::string token;
if(keys.empty()){return token;}
for(const auto& k : keys)
{
token += this->serialize_key(k);
token += '.';
}
token.erase(token.size() - 1, 1); // remove trailing `.`
return token;
}
std::string escape_basic_string(const std::string& s) const
{
//XXX assuming `s` is a valid utf-8 sequence.
@@ -513,19 +469,7 @@ struct serializer
case '\f': {retval += "\\f"; break;}
case '\n': {retval += "\\n"; break;}
case '\r': {retval += "\\r"; break;}
default :
{
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
{
retval += "\\u00";
retval += char(48 + (c / 16));
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
}
else
{
retval += c;
}
}
default : {retval += c; break;}
}
}
return retval;
@@ -539,9 +483,7 @@ struct serializer
switch(*i)
{
case '\\': {retval += "\\\\"; break;}
// One or two consecutive "s are allowed.
// Later we will check there are no three consecutive "s.
// case '\"': {retval += "\\\""; break;}
case '\"': {retval += "\\\""; break;}
case '\b': {retval += "\\b"; break;}
case '\t': {retval += "\\t"; break;}
case '\f': {retval += "\\f"; break;}
@@ -559,39 +501,8 @@ struct serializer
}
break;
}
default :
{
const auto c = *i;
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
{
retval += "\\u00";
retval += char(48 + (c / 16));
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
default: {retval += *i; break;}
}
else
{
retval += c;
}
}
}
}
// Only 1 or 2 consecutive `"`s are allowed in multiline basic string.
// 3 consecutive `"`s are considered as a closing delimiter.
// We need to check if there are 3 or more consecutive `"`s and insert
// backslash to break them down into several short `"`s like the `str6`
// in the following example.
// ```toml
// str4 = """Here are two quotation marks: "". Simple enough."""
// # str5 = """Here are three quotation marks: """.""" # INVALID
// str5 = """Here are three quotation marks: ""\"."""
// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
// ```
auto found_3_quotes = retval.find("\"\"\"");
while(found_3_quotes != std::string::npos)
{
retval.replace(found_3_quotes, 3, "\"\"\\\"");
found_3_quotes = retval.find("\"\"\"");
}
return retval;
}
@@ -629,10 +540,8 @@ struct serializer
for(const auto& item : v)
{
if(is_first) {is_first = false;} else {token += ',';}
token += visit(serializer(
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
/*has_comment*/ !item.comments().empty()), item);
token += visit(serializer(std::numeric_limits<std::size_t>::max(),
this->float_prec_, true), item);
}
token += ']';
return token;
@@ -649,12 +558,10 @@ struct serializer
{
// in inline tables, trailing comma is not allowed (toml-lang #569).
if(is_first) {is_first = false;} else {token += ',';}
token += format_key(kv.first);
token += this->serialize_key(kv.first);
token += '=';
token += visit(serializer(
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
/*has_comment*/ !kv.second.comments().empty()), kv.second);
token += visit(serializer(std::numeric_limits<std::size_t>::max(),
this->float_prec_, true), kv.second);
}
token += '}';
return token;
@@ -664,33 +571,30 @@ struct serializer
{
std::string token;
// print non-table elements first.
// ```toml
// [foo] # a table we're writing now here
// key = "value" # <- non-table element, "key"
// # ...
// [foo.bar] # <- table element, "bar"
// ```
// because after printing [foo.bar], the remaining non-table values will
// be assigned into [foo.bar], not [foo]. Those values should be printed
// earlier.
for(const auto& kv : v)
// print non-table stuff first. because after printing [foo.bar], the
// remaining non-table values will be assigned into [foo.bar], not [foo]
for(const auto kv : v)
{
if(kv.second.is_table() || is_array_of_tables(kv.second))
{
continue;
}
token += write_comments(kv.second);
const auto key_and_sep = format_key(kv.first) + " = ";
if(!kv.second.comments().empty() && !no_comment_)
{
for(const auto& c : kv.second.comments())
{
token += '#';
token += c;
token += '\n';
}
}
const auto key_and_sep = this->serialize_key(kv.first) + " = ";
const auto residual_width = (this->width_ > key_and_sep.size()) ?
this->width_ - key_and_sep.size() : 0;
token += key_and_sep;
token += visit(serializer(residual_width, this->float_prec_,
/*can be inlined*/ true, /*no comment*/ false, /*keys*/ {},
/*has_comment*/ !kv.second.comments().empty()), kv.second);
token += visit(serializer(residual_width, this->float_prec_, true),
kv.second);
if(token.back() != '\n')
{
token += '\n';
@@ -716,172 +620,45 @@ struct serializer
ks.push_back(kv.first);
auto tmp = visit(serializer(this->width_, this->float_prec_,
!multiline_table_printed, this->no_comment_, ks,
/*has_comment*/ !kv.second.comments().empty()), kv.second);
!multiline_table_printed, this->no_comment_, ks),
kv.second);
// If it is the first time to print a multi-line table, it would be
// helpful to separate normal key-value pair and subtables by a
// newline.
// (this checks if the current key-value pair contains newlines.
// but it is not perfect because multi-line string can also contain
// a newline. in such a case, an empty line will be written) TODO
if((!multiline_table_printed) &&
std::find(tmp.cbegin(), tmp.cend(), '\n') != tmp.cend())
{
multiline_table_printed = true;
token += '\n'; // separate key-value pairs and subtables
token += write_comments(kv.second);
token += tmp;
// care about recursive tables (all tables in each level prints
// newline and there will be a full of newlines)
if(tmp.substr(tmp.size() - 2, 2) != "\n\n" &&
tmp.substr(tmp.size() - 4, 4) != "\r\n\r\n" )
{
token += '\n';
}
}
else
{
token += write_comments(kv.second);
token += tmp;
// still inline tables only.
tmp += '\n';
}
if(!kv.second.comments().empty() && !no_comment_)
{
for(const auto& c : kv.second.comments())
{
token += '#';
token += c;
token += '\n';
}
}
return token;
}
std::string make_array_of_tables(const array_type& v) const
{
// if it's not inlined, we need to add `[[table.key]]`.
// but if it can be inlined, we can format it as the following.
// ```
// table.key = [
// {...},
// # comment
// {...},
// ]
// ```
// This function checks if inlinization is possible or not, and then
// format the array-of-tables in a proper way.
//
// Note about comments:
//
// If the array itself has a comment (value_has_comment_ == true), we
// should try to make it inline.
// ```toml
// # comment about array
// array = [
// # comment about table element
// {of = "table"}
// ]
// ```
// If it is formatted as a multiline table, the two comments becomes
// indistinguishable.
// ```toml
// # comment about array
// # comment about table element
// [[array]]
// of = "table"
// ```
// So we need to try to make it inline, and it force-inlines regardless
// of the line width limit.
// It may fail if the element of a table has comment. In that case,
// the array-of-tables will be formatted as a multiline table.
if(this->can_be_inlined_ || this->value_has_comment_)
{
std::string token;
if(!keys_.empty())
{
token += format_key(keys_.back());
token += " = ";
}
bool failed = false;
token += "[\n";
for(const auto& item : v)
{
// if an element of the table has a comment, the table
// cannot be inlined.
if(this->has_comment_inside(item.as_table()))
{
failed = true;
break;
}
// write comments for the table itself
token += write_comments(item);
const auto t = this->make_inline_table(item.as_table());
if(t.size() + 1 > width_ || // +1 for the last comma {...},
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
{
// if the value itself has a comment, ignore the line width limit
if( ! this->value_has_comment_)
{
failed = true;
break;
}
}
token += t;
token += ",\n";
}
if( ! failed)
{
token += "]\n";
return token;
}
// if failed, serialize them as [[array.of.tables]].
}
std::string token;
for(const auto& item : v)
{
token += write_comments(item);
token += "[[";
token += format_keys(keys_);
token += "]]\n";
token += this->make_multiline_table(item.as_table());
token += tmp;
}
return token;
}
std::string write_comments(const value_type& v) const
{
std::string retval;
if(this->no_comment_) {return retval;}
for(const auto& c : v.comments())
{
retval += '#';
retval += c;
retval += '\n';
}
return retval;
}
bool is_array_of_tables(const value_type& v) const
{
if(!v.is_array() || v.as_array().empty()) {return false;}
return is_array_of_tables(v.as_array());
}
bool is_array_of_tables(const array_type& v) const
{
// Since TOML v0.5.0, heterogeneous arrays are allowed. So we need to
// check all the element in an array to check if the array is an array
// of tables.
return std::all_of(v.begin(), v.end(), [](const value_type& elem) {
return elem.is_table();
});
if(!v.is_array()) {return false;}
const auto& a = v.as_array();
return !a.empty() && a.front().is_table();
}
private:
bool can_be_inlined_;
bool no_comment_;
bool value_has_comment_;
int float_prec_;
std::size_t width_;
std::vector<toml::key> keys_;
@@ -894,7 +671,6 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
int fprec = std::numeric_limits<toml::floating>::max_digits10,
bool no_comment = false, bool force_inline = false)
{
using value_type = basic_value<C, M, V>;
// if value is a table, it is considered to be a root object.
// the root object can't be an inline table.
if(v.is_table())
@@ -905,11 +681,10 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
oss << v.comments();
oss << '\n'; // to split the file comment from the first element
}
const auto serialized = visit(serializer<value_type>(w, fprec, false, no_comment), v);
oss << serialized;
oss << visit(serializer<C, M, V>(w, fprec, no_comment, false), v);
return oss.str();
}
return visit(serializer<value_type>(w, fprec, force_inline), v);
return visit(serializer<C, M, V>(w, fprec, force_inline), v);
}
namespace detail
@@ -926,7 +701,7 @@ template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
nocomment(std::basic_ostream<charT, traits>& os)
{
// by default, it is zero. and by default, it shows comments.
// by default, it is zero. and by defalut, it shows comments.
os.iword(detail::comment_index(os)) = 1;
return os;
}
@@ -935,7 +710,7 @@ template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
showcomment(std::basic_ostream<charT, traits>& os)
{
// by default, it is zero. and by default, it shows comments.
// by default, it is zero. and by defalut, it shows comments.
os.iword(detail::comment_index(os)) = 0;
return os;
}
@@ -945,14 +720,12 @@ template<typename charT, typename traits, typename C,
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
{
using value_type = basic_value<C, M, V>;
// get status of std::setw().
const auto w = static_cast<std::size_t>(os.width());
const int fprec = static_cast<int>(os.precision());
os.width(0);
// by default, iword is initialized by 0. And by default, toml11 outputs
// by defualt, iword is initialized byl 0. And by default, toml11 outputs
// comments. So `0` means showcomment. 1 means nocommnet.
const bool no_comment = (1 == os.iword(detail::comment_index(os)));
@@ -962,8 +735,7 @@ operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
os << '\n'; // to split the file comment from the first element
}
// the root object can't be an inline table. so pass `false`.
const auto serialized = visit(serializer<value_type>(w, fprec, no_comment, false), v);
os << serialized;
os << visit(serializer<C, M, V>(w, fprec, false, no_comment), v);
// if v is a non-table value, and has only one comment, then
// put a comment just after a value. in the following way.

View File

@@ -2,10 +2,8 @@
// Distributed under the MIT License.
#ifndef TOML11_SOURCE_LOCATION_HPP
#define TOML11_SOURCE_LOCATION_HPP
#include <cstdint>
#include <sstream>
#include "region.hpp"
#include <cstdint>
namespace toml
{
@@ -40,21 +38,17 @@ struct source_location
public:
source_location()
: line_num_(1), column_num_(1), region_size_(1),
: line_num_(0), column_num_(0), region_size_(0),
file_name_("unknown file"), line_str_("")
{}
explicit source_location(const detail::region_base* reg)
: line_num_(1), column_num_(1), region_size_(1),
: line_num_(0), column_num_(0), region_size_(0),
file_name_("unknown file"), line_str_("")
{
if(reg)
{
if(reg->line_num() != detail::region_base().line_num())
{
line_num_ = static_cast<std::uint_least32_t>(
std::stoul(reg->line_num()));
}
line_num_ = static_cast<std::uint_least32_t>(std::stoul(reg->line_num()));
column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
region_size_ = static_cast<std::uint_least32_t>(reg->size());
file_name_ = reg->name();
@@ -62,21 +56,6 @@ struct source_location
}
}
explicit source_location(const detail::region& reg)
: line_num_(static_cast<std::uint_least32_t>(std::stoul(reg.line_num()))),
column_num_(static_cast<std::uint_least32_t>(reg.before() + 1)),
region_size_(static_cast<std::uint_least32_t>(reg.size())),
file_name_(reg.name()),
line_str_ (reg.line())
{}
explicit source_location(const detail::location& loc)
: line_num_(static_cast<std::uint_least32_t>(std::stoul(loc.line_num()))),
column_num_(static_cast<std::uint_least32_t>(loc.before() + 1)),
region_size_(static_cast<std::uint_least32_t>(loc.size())),
file_name_(loc.name()),
line_str_ (loc.line())
{}
~source_location() = default;
source_location(source_location const&) = default;
source_location(source_location &&) = default;
@@ -99,141 +78,5 @@ struct source_location
std::string line_str_;
};
namespace detail
{
// internal error message generation.
inline std::string format_underline(const std::string& message,
const std::vector<std::pair<source_location, std::string>>& loc_com,
const std::vector<std::string>& helps = {},
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
{
std::size_t line_num_width = 0;
for(const auto& lc : loc_com)
{
std::uint_least32_t line = lc.first.line();
std::size_t digit = 0;
while(line != 0)
{
line /= 10;
digit += 1;
}
line_num_width = (std::max)(line_num_width, digit);
}
// 1 is the minimum width
line_num_width = std::max<std::size_t>(line_num_width, 1);
std::ostringstream retval;
if(color::should_color() || colorize)
{
retval << color::colorize; // turn on ANSI color
}
// XXX
// Here, before `colorize` support, it does not output `[error]` prefix
// automatically. So some user may output it manually and this change may
// duplicate the prefix. To avoid it, check the first 7 characters and
// if it is "[error]", it removes that part from the message shown.
if(message.size() > 7 && message.substr(0, 7) == "[error]")
{
retval
#ifndef TOML11_NO_ERROR_PREFIX
<< color::bold << color::red << "[error]" << color::reset
#endif
<< color::bold << message.substr(7) << color::reset << '\n';
}
else
{
retval
#ifndef TOML11_NO_ERROR_PREFIX
<< color::bold << color::red << "[error] " << color::reset
#endif
<< color::bold << message << color::reset << '\n';
}
const auto format_one_location = [line_num_width]
(std::ostringstream& oss,
const source_location& loc, const std::string& comment) -> void
{
oss << ' ' << color::bold << color::blue
<< std::setw(static_cast<int>(line_num_width))
<< std::right << loc.line() << " | " << color::reset
<< loc.line_str() << '\n';
oss << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " | " << color::reset
<< make_string(loc.column()-1 /*1-origin*/, ' ');
if(loc.region() == 1)
{
// invalid
// ^------
oss << color::bold << color::red << "^---" << color::reset;
}
else
{
// invalid
// ~~~~~~~
const auto underline_len = (std::min)(
static_cast<std::size_t>(loc.region()), loc.line_str().size());
oss << color::bold << color::red
<< make_string(underline_len, '~') << color::reset;
}
oss << ' ';
oss << comment;
return;
};
assert(!loc_com.empty());
// --> example.toml
// |
retval << color::bold << color::blue << " --> " << color::reset
<< loc_com.front().first.file_name() << '\n';
retval << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " |\n" << color::reset;
// 1 | key value
// | ^--- missing =
format_one_location(retval, loc_com.front().first, loc_com.front().second);
// process the rest of the locations
for(std::size_t i=1; i<loc_com.size(); ++i)
{
const auto& prev = loc_com.at(i-1);
const auto& curr = loc_com.at(i);
retval << '\n';
// if the filenames are the same, print "..."
if(prev.first.file_name() == curr.first.file_name())
{
retval << color::bold << color::blue << " ...\n" << color::reset;
}
else // if filename differs, print " --> filename.toml" again
{
retval << color::bold << color::blue << " --> " << color::reset
<< curr.first.file_name() << '\n';
retval << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " |\n" << color::reset;
}
format_one_location(retval, curr.first, curr.second);
}
if(!helps.empty())
{
retval << '\n';
retval << make_string(line_num_width + 1, ' ');
retval << color::bold << color::blue << " |" << color::reset;
for(const auto& help : helps)
{
retval << color::bold << "\nHint: " << color::reset;
retval << help;
}
}
return retval.str();
}
} // detail
} // toml
#endif// TOML11_SOURCE_LOCATION_HPP

View File

@@ -16,9 +16,10 @@ struct storage
{
using value_type = T;
explicit storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
explicit storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
~storage() = default;
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
storage& operator=(const storage& rhs)
{

View File

@@ -2,17 +2,10 @@
// Distributed under the MIT License.
#ifndef TOML11_STRING_HPP
#define TOML11_STRING_HPP
#include "version.hpp"
#include <cstdint>
#include <algorithm>
#include <string>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <cstdint>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#define TOML11_USING_STRING_VIEW 1
#include <string_view>
#endif
#endif
@@ -52,12 +45,7 @@ struct string
operator std::string const& () const& noexcept {return str;}
operator std::string&& () && noexcept {return std::move(str);}
string& operator+=(const char* rhs) {str += rhs; return *this;}
string& operator+=(const char rhs) {str += rhs; return *this;}
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
#if __cplusplus >= 201703L
explicit string(std::string_view s): kind(string_t::basic), str(s){}
string(std::string_view s, string_t k): kind(k), str(s){}
@@ -66,8 +54,6 @@ struct string
explicit operator std::string_view() const noexcept
{return std::string_view(str);}
string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
#endif
string_t kind;

View File

@@ -2,19 +2,12 @@
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include "from.hpp"
#include "into.hpp"
#include "version.hpp"
#include <chrono>
#include <forward_list>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#include <chrono>
#include <tuple>
#include <string>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
@@ -50,23 +43,17 @@ struct has_mapped_type_impl
template<typename T> static std::true_type check(typename T::mapped_type*);
template<typename T> static std::false_type check(...);
};
struct has_reserve_method_impl
struct has_resize_method_impl
{
constexpr static std::size_t dummy=0;
template<typename T> static std::true_type check(decltype(std::declval<T>().resize(dummy))*);
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
};
struct has_push_back_method_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
};
struct is_comparable_impl
{
template<typename T> static std::true_type check(decltype(std::declval<T>() < std::declval<T>())*);
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>() < std::declval<T>())*);
};
struct has_from_toml_method_impl
@@ -89,22 +76,6 @@ struct has_into_toml_method_impl
static std::false_type check(...);
};
struct has_specialized_from_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
static std::true_type check(::toml::from<T>*);
};
struct has_specialized_into_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
static std::true_type check(::toml::from<T>*);
};
/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
@@ -120,9 +91,7 @@ struct has_key_type : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
@@ -135,26 +104,13 @@ template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};
#ifdef __INTEL_COMPILER
#undef decltype
#undef decltype(...)
#endif
// ---------------------------------------------------------------------------
// C++17 and/or/not
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
using std::conjunction;
using std::disjunction;
using std::negation;
#else
template<typename ...> struct conjunction : std::true_type{};
template<typename T> struct conjunction<T> : T{};
template<typename T, typename ... Ts>
@@ -172,8 +128,6 @@ struct disjunction<T, Ts...> :
template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
#endif
// ---------------------------------------------------------------------------
// type checkers
@@ -185,10 +139,6 @@ template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
template<typename T> struct is_std_forward_list : std::false_type{};
template<typename T>
struct is_std_forward_list<std::forward_list<T>> : std::true_type{};
template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
@@ -209,10 +159,8 @@ template<typename T>
struct is_container : conjunction<
negation<is_map<T>>, // not a map
negation<std::is_same<T, std::string>>, // not a std::string
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __has_include(<string_view>)
#if __cplusplus >= 201703L
negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif // has_include(<string_view>)
#endif
has_iterator<T>, // has T::iterator
has_value_type<T> // has T::value_type
@@ -234,13 +182,6 @@ struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
// ---------------------------------------------------------------------------
// C++14 index_sequence
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::index_sequence;
using std::make_index_sequence;
#else
template<std::size_t ... Ns> struct index_sequence{};
template<typename IS, std::size_t N> struct push_back_index_sequence{};
@@ -264,26 +205,15 @@ struct index_sequence_maker<0>
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;
#endif // cplusplus >= 2014
// ---------------------------------------------------------------------------
// C++14 enable_if_t
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::enable_if_t;
#else
template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;
#endif // cplusplus >= 2014
// ---------------------------------------------------------------------------
// return_type_of_t
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703
#if __cplusplus >= 201703L
template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;
@@ -310,19 +240,6 @@ disjunction<
>
>{};
// ---------------------------------------------------------------------------
// C++20 remove_cvref_t
template<typename T>
struct remove_cvref
{
using type = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
};
template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;
}// detail
}//toml
#endif // TOML_TRAITS

View File

@@ -2,13 +2,12 @@
// Distributed under the MIT License.
#ifndef TOML11_TYPES_HPP
#define TOML11_TYPES_HPP
#include <unordered_map>
#include <vector>
#include "comments.hpp"
#include "datetime.hpp"
#include "string.hpp"
#include "traits.hpp"
#include "comments.hpp"
#include <vector>
#include <unordered_map>
namespace toml
{
@@ -21,14 +20,9 @@ class basic_value;
using character = char;
using key = std::string;
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ <= 4
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wshadow"
#endif
using boolean = bool;
using integer = std::int64_t;
using floating = double; // "float" is a keyword, cannot use it here.
using floating = double; // "float" is a keyward, cannot use it here.
// the following stuffs are structs defined here, so aliases are not needed.
// - string
// - offset_datetime
@@ -37,26 +31,12 @@ using floating = double; // "float" is a keyword, cannot use it here.
// - local_date
// - local_time
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
// default toml::value and default array/table. these are defined after defining
// basic_value itself.
// using value = basic_value<discard_comments, std::unordered_map, std::vector>;
// using array = typename value::array_type;
// using table = typename value::table_type;
// to avoid warnings about `value_t::integer` is "shadowing" toml::integer in
// GCC -Wshadow=global.
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# if 7 <= __GNUC__
# pragma GCC diagnostic ignored "-Wshadow=global"
# else // gcc-6 or older
# pragma GCC diagnostic ignored "-Wshadow"
# endif
#endif
enum class value_t : std::uint8_t
{
empty = 0,
@@ -71,9 +51,6 @@ enum class value_t : std::uint8_t
array = 9,
table = 10,
};
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
template<typename charT, typename traits>
inline std::basic_ostream<charT, traits>&
@@ -169,5 +146,4 @@ template<typename T, typename V> struct is_exact_toml_type<T const volatile&, V>
} // detail
} // toml
#endif// TOML11_TYPES_H

View File

@@ -2,14 +2,12 @@
// Distributed under the MIT License.
#ifndef TOML11_UTILITY_HPP
#define TOML11_UTILITY_HPP
#include "traits.hpp"
#include <utility>
#include <memory>
#include <sstream>
#include <utility>
#include "traits.hpp"
#include "version.hpp"
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
#if __cplusplus >= 201402L
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
#elif defined(__GNUC__)
# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg)))
@@ -22,41 +20,38 @@
namespace toml
{
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::make_unique;
#else
template<typename T, typename ... Ts>
inline std::unique_ptr<T> make_unique(Ts&& ... args)
{
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
}
#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014
namespace detail
{
template<typename Container>
void try_reserve_impl(Container& container, std::size_t N, std::true_type)
template<typename T>
inline void resize_impl(T& container, std::size_t N, std::true_type)
{
container.reserve(N);
return;
container.resize(N);
return ;
}
template<typename Container>
void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
template<typename T>
inline void resize_impl(T& container, std::size_t N, std::false_type)
{
return;
if(container.size() >= N) {return;}
throw std::invalid_argument("not resizable type");
}
} // detail
template<typename Container>
void try_reserve(Container& container, std::size_t N)
template<typename T>
inline void resize(T& container, std::size_t N)
{
if(N <= container.size()) {return;}
detail::try_reserve_impl(container, N, detail::has_reserve_method<Container>{});
return;
if(container.size() == N) {return;}
return detail::resize_impl(container, N, detail::has_resize_method<T>());
}
namespace detail
@@ -81,70 +76,14 @@ std::string concat_to_string(Ts&& ... args)
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
}
template<typename T>
T from_string(const std::string& str, T opt)
template<typename T, typename U>
T from_string(const std::string& str, U&& opt)
{
T v(opt);
T v(static_cast<T>(std::forward<U>(opt)));
std::istringstream iss(str);
iss >> v;
return v;
}
namespace detail
{
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
template<typename T>
decltype(auto) last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept
{
return last_one(std::forward<Ts>(tail)...);
}
#else // C++11
// The following code
// ```cpp
// 1 | template<typename T, typename ... Ts>
// 2 | auto last_one(T&& /*head*/, Ts&& ... tail)
// 3 | -> decltype(last_one(std::forward<Ts>(tail)...))
// 4 | {
// 5 | return last_one(std::forward<Ts>(tail)...);
// 6 | }
// ```
// does not work because the function `last_one(...)` is not yet defined at
// line #3, so `decltype()` cannot deduce the type returned from `last_one`.
// So we need to determine return type in a different way, like a meta func.
template<typename T, typename ... Ts>
struct last_one_in_pack
{
using type = typename last_one_in_pack<Ts...>::type;
};
template<typename T>
struct last_one_in_pack<T>
{
using type = T;
};
template<typename ... Ts>
using last_one_in_pack_t = typename last_one_in_pack<Ts...>::type;
template<typename T>
T&& last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
enable_if_t<(sizeof...(Ts) > 0), last_one_in_pack_t<Ts&& ...>>
last_one(T&& /*head*/, Ts&& ... tail)
{
return last_one(std::forward<Ts>(tail)...);
}
#endif
} // detail
}// toml
#endif // TOML11_UTILITY

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +0,0 @@
#ifndef TOML11_VERSION_HPP
#define TOML11_VERSION_HPP
// This file checks C++ version.
#ifndef __cplusplus
# error "__cplusplus is not defined"
#endif
// Since MSVC does not define `__cplusplus` correctly unless you pass
// `/Zc:__cplusplus` when compiling, the workaround macros are added.
// Those enables you to define version manually or to use MSVC specific
// version macro automatically.
//
// The value of `__cplusplus` macro is defined in the C++ standard spec, but
// MSVC ignores the value, maybe because of backward compatibility. Instead,
// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in
// the C++ standard. First we check the manual version definition, and then
// we check if _MSVC_LANG is defined. If neither, use normal `__cplusplus`.
//
// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
//
#if defined(TOML11_ENFORCE_CXX11)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201103L
#elif defined(TOML11_ENFORCE_CXX14)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201402L
#elif defined(TOML11_ENFORCE_CXX17)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201703L
#elif defined(TOML11_ENFORCE_CXX20)
# define TOML11_CPLUSPLUS_STANDARD_VERSION 202002L
#elif defined(_MSVC_LANG) && defined(_MSC_VER) && 1910 <= _MSC_VER
# define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG
#else
# define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L && _MSC_VER < 1900
# error "toml11 requires C++11 or later."
#endif
#endif// TOML11_VERSION_HPP