new file: .circleci/config.yml

new file:   .editorconfig
new file:   .gitattributes
new file:   .gitignore
new file:   .gitmodules
new file:   LICENSE
new file:   README.md
new file:   examples/example.cpp
new file:   examples/example.toml
new file:   examples/meson.build
new file:   include/toml++/toml.h
new file:   include/toml++/toml_array.h
new file:   include/toml++/toml_common.h
new file:   include/toml++/toml_formatter.h
new file:   include/toml++/toml_node.h
new file:   include/toml++/toml_node_view.h
new file:   include/toml++/toml_parser.h
new file:   include/toml++/toml_table.h
new file:   include/toml++/toml_utf8.h
new file:   include/toml++/toml_utf8_generated.h
new file:   include/toml++/toml_value.h
new file:   meson.build
new file:   python/ci_single_header_check.py
new file:   python/generate_single_header.py
new file:   python/generate_unicode_functions.py
new file:   tests/catch2
new file:   tests/catch2.h
new file:   tests/lifetimes.cpp
new file:   tests/main.cpp
new file:   tests/meson.build
new file:   tests/parsing_arrays.cpp
new file:   tests/parsing_booleans.cpp
new file:   tests/parsing_comments.cpp
new file:   tests/parsing_dates_and_times.cpp
new file:   tests/parsing_floats.cpp
new file:   tests/parsing_integers.cpp
new file:   tests/parsing_key_value_pairs.cpp
new file:   tests/parsing_spec_example.cpp
new file:   tests/parsing_strings.cpp
new file:   tests/parsing_tables.cpp
new file:   tests/tests.cpp
new file:   tests/tests.h
new file:   toml.hpp
new file:   vs/.runsettings
new file:   vs/example.vcxproj
new file:   vs/test_char.vcxproj
new file:   vs/test_char8.vcxproj
new file:   vs/test_char8_noexcept.vcxproj
new file:   vs/test_char_noexcept.vcxproj
new file:   vs/test_strict_char.vcxproj
new file:   vs/test_strict_char8.vcxproj
new file:   vs/test_strict_char8_noexcept.vcxproj
new file:   vs/test_strict_char_noexcept.vcxproj
new file:   vs/toml++.natvis
new file:   vs/toml++.props
new file:   vs/toml++.sln
new file:   vs/toml++.vcxproj
new file:   vs/toml++.vcxproj.filters
This commit is contained in:
Mark Gillard 2020-01-04 16:21:38 +02:00
commit 930bf0ad58
58 changed files with 17421 additions and 0 deletions

45
.circleci/config.yml Normal file
View File

@ -0,0 +1,45 @@
version: 2.1
jobs:
linux_build:
docker:
- image: "debian:bullseye"
steps:
- checkout
- run:
name: Installing python
command: |
apt-get -qq update && apt-get install -y python3
- run:
name: Checking toml.hpp
command: |
cd python && python3 ci_single_header_check.py
- run:
name: Installing applications
command: |
apt-get -qq update && apt-get install -y git clang-9 g++-9 python3-pip ninja-build
pip3 install meson
- run:
name: Pulling submodules
command: |
git submodule update --init --recursive
- run:
name: Building with clang
command: |
CXX=clang++-9 meson build-clang
cd build-clang && ninja -v -j 4
- run:
name: Building with gcc
command: |
CXX=g++-9 meson build-gcc
cd build-gcc && ninja -v -j 4
- run:
name: Running tests
command: |
cd build-clang && ninja test && cd ../build-gcc && ninja test
workflows:
version: 2
build:
jobs:
- linux_build

17
.editorconfig Normal file
View File

@ -0,0 +1,17 @@
root = true
[*]
insert_final_newline = true
indent_style = tab
indent_size = 4
tab_width = 4
[*.{gitattributes, yml}]
indent_style = space
[*.{c, cpp, cxx, h, hpp, hxx, inl, toml, xml, py, natvis, props, build, yml}]
charset = utf-8
trim_trailing_whitespace = true
[*.{c, cpp, cxx, h, hpp, hxx, inl, py, md}]
end_of_line = lf

17
.gitattributes vendored Normal file
View File

@ -0,0 +1,17 @@
* text=auto encoding=UTF-8
*.c text encoding=UTF-8 eol=lf
*.cpp text encoding=UTF-8 eol=lf
*.cxx text encoding=UTF-8 eol=lf
*.h text encoding=UTF-8 eol=lf
*.hpp text encoding=UTF-8 eol=lf
*.hxx text encoding=UTF-8 eol=lf
*.inl text encoding=UTF-8 eol=lf
*.toml text=auto encoding=UTF-8
*.xml text=auto encoding=UTF-8
*.py text encoding=UTF-8 eol=lf
*.natvis text encoding=UTF-8 eol=crlf
*.props text encoding=UTF-8 eol=crlf
*.vcxproj text encoding=UTF-8 eol=crlf
*.sln text encoding=UTF-8-BOM eol=crlf
*.runsettings text encoding=UTF-8 eol=crlf
*.md text encoding=UTF-8 eol=lf

359
.gitignore vendored Normal file
View File

@ -0,0 +1,359 @@
UnicodeData.txt
meson-info/
meson-logs/
meson-private/
*.o
.ninja_*
build.ninja
compile_commands.json
[Bb]uild*/
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
*.Designer.cs.dll
unsuccessfulbuild
*.lastbuildstate
*.psess
*.vsp
*.vspx
*.tlog
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp
*.lnk

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "tests/catch2"]
path = tests/catch2
url = https://github.com/catchorg/Catch2.git

18
LICENSE Normal file
View File

@ -0,0 +1,18 @@
MIT License
Copyright (c) 2019 Mark Gillard
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

142
README.md Normal file
View File

@ -0,0 +1,142 @@
# toml++ (tomlplusplus)
Header-only [TOML v0.5.0] parsing lib for C++17 and later.
[![CircleCI](https://circleci.com/gh/marzer/tomlplusplus.svg?style=shield)](https://circleci.com/gh/marzer/tomlplusplus)
<br>
# Usage
`toml++` comes in two flavours: Regular and Single-header.
### Regular mode
1. Add `tomlplusplus/include` to your include paths
2. `#include <toml++/toml.h>`
### Single-header mode
1. Drop `toml.hpp` somewhere in your source tree
2. There is no step two
The API is the same regardless of how you consume the library. You'll find code examples in
the `examples` directory.
<br>
# Configuration
A number of configurable options are exposed in the form of preprocessor macros. Most likely you
won't need to mess with these at all, but in the event you do, set your overrides prior to including
toml++.
| Option | Type | Default | Description |
|----------------------------|:--------------:|-----------------------------------|-----------------------------------------------------------------------------------------------|
| `TOML_ASSERT(expr)` | function macro | `assert(expr)`<br>(or undefined) | Sets the assert function used by the library. |
| `TOML_CHAR_8_STRINGS` | boolean | `0` | Uses C++20 [char8_t]-based strings as the toml string data type. |
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_UNDEF_MACROS` | boolean | `1` | `#undefs` the library's internal macros at the end of the header. |
| `TOML_UNRELEASED_FEATURES` | boolean | `1` | Enables support for [unreleased TOML language features] not yet part of a [numbered version]. |
<br>
# TOML Language Support
At any given time `toml++` aims to implement whatever the [numbered version] of TOML is, with the
addition of unreleased features from the [TOML master] and some sane cherry-picks from the
[TOML issues list] where the discussion strongly indicates inclusion in a near-future release.
The library advertises the most recent numbered language version it fully supports via the preprocessor
defines `TOML_LANG_MAJOR`, `TOML_LANG_MINOR` and `TOML_LANG_REVISION`.
### **🔸Unreleased features:**
- [#356]: Allow leading zeros in the exponent part of a float
- [#516]: Allow newlines and trailing commas in inline tables
- [#562]: Allow hex floatingpoint values
- [#567]: Clarify that control characters are not permitted in comments
- [#571]: Allow raw tabs inside strings
- [#622]: Add short escaping alias `\s` for space (`\u0020`)
- [#644]: Support `+` in key names
- [#665]: Make arrays heterogeneous
- [#671]: Local time of day format should support `09:30` as opposed to `09:30:00`
- [#687]: Relax bare key restrictions to allow additional unicode characters
_These can be disabled (and thus strict [TOML v0.5.0] compliance enforced) by specifying
`TOML_UNRELEASED_FEATURES = 0` (see [Configuration](#Configuration))._
### **🔹[v0.5.0](https://github.com/toml-lang/toml/releases/tag/v0.5.0) and earlier:**
- All features as of `<< release date >>`.
<br>
# Contributing
Contributions are welcome, either by [reporting issues](https://github.com/marzer/tomlplusplus/issues)
or submitting pull requests. If you wish to submit a PR, please be aware that:
- The single-header file `toml.hpp` is generated by a script; make your changes in the files in
`include`, **not** in `toml.hpp`.
- Your changes should compile warning-free on at least gcc 8.3.0, clang 8.0, and MSVC 19.2X
(Visual Studio 2019).
- You should regenerate the single-header file as part of your PR (a CI check will fail if you don't).
### Regenerating toml.hpp
1. Make your changes as necessary
2. If you've added a new header file that isn't going to be transitively included by one of the
others, add an include directive to `include/toml++/toml.h`
3. Run `python/generate_single_header.py`
### Building and testing
Testing is done using [catch2], included in the respository as a submodule under `tests/catch2`.
The first time you want to begin testing you'll need to ensure submodules have been fetched:
```bash
git submodule update --init --recursive
```
#### Windows
Install [Visual Studio 2019] and [Test Adapter for Catch2], then open `vs/toml++.sln` and build the
projects in the `tests` solution folder. Visual Studio's Test Explorer should pick these up and
allow you to run the tests directly.
If test discovery fails, you can usually fix it by clicking enabling
`Auto Detect runsettings Files` (settings gear icon > `Configure Run Settings`).
#### Linux
Install [meson] and [ninja] if necessary, then test with both gcc and clang:
```bash
CXX=g++ meson build-gcc
CXX=clang++ meson build-clang
cd build-gcc
ninja && ninja test
cd ../build-clang
ninja && ninja test
```
<br>
# License and Attribution
`toml++` is licensed under the terms of the MIT license - See [LICENSE].
UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[Flexible and Economical UTF-8 Decoder]',
which is itself subject to the terms of the MIT license. The license text is included in the
[relevant part](https://github.com/marzer/tomlplusplus/blob/master/include/toml%2B%2B/toml_utf8.h)
of the toml++ source.
[unreleased TOML language features]: https://github.com/marzer/tomlplusplus#unreleased-features
[numbered version]: https://github.com/toml-lang/toml/releases
[char8_t]: https://en.cppreference.com/w/cpp/keyword/char8_t
[TOML master]: https://github.com/toml-lang/toml/blob/master/README.md
[TOML issues list]: https://github.com/toml-lang/toml/issues
[TOML v0.5.0]: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md
[LICENSE]: https://github.com/marzer/tomlplusplus/blob/master/LICENSE
[Flexible and Economical UTF-8 Decoder]: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
[meson]: https://mesonbuild.com/Getting-meson.html
[ninja]: https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages
[catch2]: https://github.com/catchorg/Catch2
[Test Adapter for Catch2]: https://marketplace.visualstudio.com/items?itemName=JohnnyHendriks.ext01
[Visual Studio 2019]: https://visualstudio.microsoft.com/vs/
[#356]: https://github.com/toml-lang/toml/issues/356
[#516]: https://github.com/toml-lang/toml/issues/516
[#562]: https://github.com/toml-lang/toml/issues/562
[#567]: https://github.com/toml-lang/toml/issues/567
[#571]: https://github.com/toml-lang/toml/issues/571
[#622]: https://github.com/toml-lang/toml/issues/622
[#644]: https://github.com/toml-lang/toml/issues/644
[#665]: https://github.com/toml-lang/toml/issues/665
[#671]: https://github.com/toml-lang/toml/issues/671
[#687]: https://github.com/toml-lang/toml/issues/687

45
examples/example.cpp Normal file
View File

@ -0,0 +1,45 @@
#include <toml++/toml.h>
#include <iostream>
#include <fstream>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
using namespace std::string_view_literals;
int main(int argc, char** argv)
{
#ifdef _WIN32
SetConsoleOutputCP(65001);
#endif
auto path = std::string{ argc > 1 ? argv[1] : "example.toml" };
auto file = std::ifstream{ path };
if (!file)
{
std::cerr << "The file '"sv << path << "' could not be opened for reading."sv << std::endl;
return 1;
}
try
{
//const auto table = toml::parse(file); //works but parse_errors would not include the source path
const auto table = toml::parse(file, std::move(path));
std::cout << table << std::endl;
}
catch (const toml::parse_error& err)
{
std::cerr
<< "Error parsing file '"sv << *err.where().path
<< "' at line "sv << err.where().begin.line
<< ", column "sv << err.where().begin.column
<< ":\n"sv << err.what()
<< std::endl;
return 1;
}
return 0;
}

94
examples/example.toml Normal file
View File

@ -0,0 +1,94 @@
# This is a TOML document. Boom.
title = "TOML Example"
# plain signed integers
int1 = -9223372036854775808
int2 = 9223372036854775807
# floats
flt1 = 0.00000000001
flt2 = 1e-11
flt3 = 11.0
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110 # 214
# local dates and times
tim1 = 07:32:00
tim2 = 00:32:00.100000000
dat1 = 1979-05-27
# offset date-times
odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00
# unicode
kosme = "κόσμε"
arr = [ 'this', 'is', 'a', 'long', 'array', 'with', 16, 'elements.', 'it', 'should', 'be', 'printed', 'as', 'a', 'multiline', 'array.']
tab = { this = 'is', an = 'inline', table = 'yay'}
dotted.keys.are = "supported"
dotted.and = "implemented as tables"
[owner]
name = "Mark Gillard"
dob = 1987-03-16 10:20:00+09:30
[[owner.pets]]
name = "Brian"
species = "cat"
[[owner.pets]]
name = "Skippy"
species = "kangaroo"
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# You can indent as you please. Tabs or spaces. TOML don't care.
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
country = "中国" # This should be parsed as UTF-8
[clients]
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]
# Products
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
name = "Nail"
sku = 284758393
color = "gray"

5
examples/meson.build Normal file
View File

@ -0,0 +1,5 @@
example = executable(
'example',
[ 'example.cpp' ],
include_directories : inc
)

49
include/toml++/toml.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
//# Note: most of these would be included transitively but
//# they're listed explicitly here because this file
//# is used as the source for generate_single_header.py.
#include "toml_common.h"
#include "toml_node.h"
#include "toml_table.h"
#include "toml_array.h"
#include "toml_value.h"
#include "toml_utf8.h"
#include "toml_node_view.h"
#include "toml_parser.h"
#include "toml_formatter.h"
//macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_EXCEPTIONS
#undef TOML_USE_STREAMS_FOR_FLOATS
#undef TOML_PUSH_WARNINGS
#undef TOML_DISABLE_SWITCH_WARNING
#undef TOML_DISABLE_FIELD_INIT_WARNING
#undef TOML_DISABLE_VAR_INIT_WARNING
#undef TOML_DISABLE_ALL_WARNINGS
#undef TOML_POP_WARNINGS
#undef TOML_ALWAYS_INLINE
#undef TOML_ASSUME
#undef TOML_UNREACHABLE
#undef TOML_INTERFACE
#undef TOML_EMPTY_BASES
#undef TOML_CPP
#undef TOML_CONDITIONAL_NOEXCEPT
#undef TOML_MAY_THROW
#undef TOML_NO_DEFAULT_CASE
#undef TOML_CONSTEVAL
#undef TOML_LIKELY
#undef TOML_UNLIKELY
#undef TOML_NO_UNIQUE_ADDRESS
#undef TOML_NODISCARD_CTOR
#undef TOML_LANG_MAKE_VERSION
#undef TOML_LANG_EFFECTIVE_VERSION
#undef TOML_LANG_HIGHER_THAN
#undef TOML_LANG_AT_LEAST
#undef TOML_LANG_EXACTLY
#undef TOML_STRING_PREFIX_1
#undef TOML_STRING_PREFIX
#undef TOML_UNDEF_MACROS
#endif

View File

@ -0,0 +1,83 @@
#pragma once
#include "toml_node.h"
namespace toml
{
class array final
: public node
{
private:
friend class impl::parser;
friend class default_formatter;
std::vector<std::unique_ptr<node>> values;
public:
TOML_NODISCARD_CTOR
array() noexcept = default;
TOML_NODISCARD_CTOR
array(array&& other) noexcept
: node{ std::move(other) },
values{ std::move(other.values) }
{}
array& operator= (array&& rhs) noexcept
{
node::operator=(std::move(rhs));
values = std::move(rhs.values);
return *this;
}
[[nodiscard]] bool is_array() const noexcept override { return true; }
[[nodiscard]] bool is_array_of_tables() const noexcept override
{
if (values.empty())
return false;
for (auto& val : values)
if (!val->is_table())
return false;
return true;
}
[[nodiscard]]
bool is_homogeneous() const noexcept
{
if (values.size() <= 1_sz)
return true;
const auto type = values[0]->type();
for (size_t i = 1; i < values.size(); i++)
if (values[i]->type() != type)
return false;
return true;
}
[[nodiscard]] array* as_array() noexcept override { return this; }
[[nodiscard]] const array* as_array() const noexcept override { return this; }
[[nodiscard]] node_type type() const noexcept override { return node_type::array; }
[[nodiscard]] size_t size() const noexcept { return values.size(); }
[[nodiscard]] node* get(size_t index) noexcept { return values[index].get(); }
[[nodiscard]] const node* get(size_t index) const noexcept { return values[index].get(); }
template <typename T>
[[nodiscard]]
node_of<T>* get_as(size_t index) noexcept
{
return get(index)->as<T>();
}
template <typename T>
[[nodiscard]]
const node_of<T>* get_as(size_t index) const noexcept
{
return get(index)->as<T>();
}
};
}

View File

@ -0,0 +1,623 @@
#pragma once
////////// CONFIGURATION
// clang-format off
#ifdef TOML_CONFIG_HEADER
#include TOML_CONFIG_HEADER
#undef TOML_CONFIG_HEADER
#endif
#ifndef TOML_CHAR_8_STRINGS
#define TOML_CHAR_8_STRINGS 0
#endif
#ifndef TOML_UNRELEASED_FEATURES
#define TOML_UNRELEASED_FEATURES 1
#endif
#ifndef TOML_ASSERT
#ifdef assert
#define TOML_ASSERT(expr) assert(expr)
#else
#define TOML_ASSERT(expr) (void)0
#endif
#endif
#ifndef TOML_UNDEF_MACROS
#define TOML_UNDEF_MACROS 1
#endif
////////// COMPILER & ENVIRONMENT STUFF
#ifndef __cplusplus
#error toml++ is a C++ library.
#endif
#ifdef __clang__
#ifndef __cpp_exceptions
#define TOML_EXCEPTIONS 0
#endif
#define TOML_PUSH_WARNINGS _Pragma("clang diagnostic push")
#define TOML_DISABLE_SWITCH_WARNING _Pragma("clang diagnostic ignored \"-Wswitch\"")
#define TOML_DISABLE_FIELD_INIT_WARNING _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"")
#define TOML_DISABLE_ALL_WARNINGS _Pragma("clang diagnostic ignored \"-Weverything\"")
#define TOML_POP_WARNINGS _Pragma("clang diagnostic pop")
#define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
#define TOML_ASSUME(cond) __builtin_assume(cond)
#define TOML_UNREACHABLE __builtin_unreachable()
#if __has_declspec_attribute(novtable)
#define TOML_INTERFACE __declspec(novtable)
#endif
#if __has_declspec_attribute(empty_bases)
#define TOML_EMPTY_BASES __declspec(empty_bases)
#endif
//floating-point from_chars and to_chars are not implemented in any version of clang as of 1/1/2020
#ifndef TOML_USE_STREAMS_FOR_FLOATS
#define TOML_USE_STREAMS_FOR_FLOATS 1
#endif
#elif defined(_MSC_VER)
#ifndef _CPPUNWIND
#define TOML_EXCEPTIONS 0
#endif
#define TOML_CPP_VERSION _MSVC_LANG
#define TOML_PUSH_WARNINGS __pragma(warning(push))
#define TOML_DISABLE_SWITCH_WARNING __pragma(warning(disable: 4063))
#define TOML_DISABLE_ALL_WARNINGS __pragma(warning(pop)) \
__pragma(warning(push, 0))
#define TOML_POP_WARNINGS __pragma(warning(pop))
#define TOML_ALWAYS_INLINE __forceinline
#define TOML_ASSUME(cond) __assume(cond)
#define TOML_UNREACHABLE __assume(0)
#define TOML_INTERFACE __declspec(novtable)
#define TOML_EMPTY_BASES __declspec(empty_bases)
#elif defined(__GNUC__)
#ifndef __cpp_exceptions
#define TOML_EXCEPTIONS 0
#endif
#define TOML_PUSH_WARNINGS _Pragma("GCC diagnostic push")
#define TOML_DISABLE_SWITCH_WARNING _Pragma("GCC diagnostic ignored \"-Wswitch\"")
#define TOML_DISABLE_FIELD_INIT_WARNING _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
#define TOML_DISABLE_VAR_INIT_WARNING _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
#define TOML_DISABLE_ALL_WARNINGS _Pragma("GCC diagnostic ignored \"-Wall\"")
#define TOML_POP_WARNINGS _Pragma("GCC diagnostic pop")
#define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
#define TOML_UNREACHABLE __builtin_unreachable()
//floating-point from_chars and to_chars are not implemented in any version of gcc as of 1/1/2020
#ifndef TOML_USE_STREAMS_FOR_FLOATS
#define TOML_USE_STREAMS_FOR_FLOATS 1
#endif
#endif
#ifndef TOML_CPP_VERSION
#define TOML_CPP_VERSION __cplusplus
#endif
#if TOML_CPP_VERSION >= 202600L
#define TOML_CPP 26
#elif TOML_CPP_VERSION >= 202300L
#define TOML_CPP 23
#elif TOML_CPP_VERSION >= 202000L
#define TOML_CPP 20
#elif TOML_CPP_VERSION >= 201703L
#define TOML_CPP 17
#elif TOML_CPP_VERSION >= 201100L
#error toml++ requires C++17 or higher. For a TOML parser that supports C++11 see https://github.com/skystrife/cpptoml
#else
#error toml++ requires C++17 or higher. For a TOML parser that supports pre-C++11 see https://github.com/ToruNiina/Boost.toml
#endif
#undef TOML_CPP_VERSION
#ifndef TOML_EXCEPTIONS
#define TOML_EXCEPTIONS 1
#endif
#if TOML_EXCEPTIONS
#define TOML_CONDITIONAL_NOEXCEPT(...) noexcept(__VA_ARGS__)
#define TOML_MAY_THROW
#else
#define TOML_CONDITIONAL_NOEXCEPT(...) noexcept
#define TOML_MAY_THROW noexcept
#endif
#ifndef TOML_DISABLE_FIELD_INIT_WARNING
#define TOML_DISABLE_FIELD_INIT_WARNING
#endif
#ifndef TOML_DISABLE_VAR_INIT_WARNING
#define TOML_DISABLE_VAR_INIT_WARNING
#endif
#ifndef TOML_USE_STREAMS_FOR_FLOATS
#define TOML_USE_STREAMS_FOR_FLOATS 0
#endif
#ifndef TOML_PUSH_WARNINGS
#define TOML_PUSH_WARNINGS
#endif
#ifndef TOML_DISABLE_ALL_WARNINGS
#define TOML_DISABLE_ALL_WARNINGS
#endif
#ifndef TOML_POP_WARNINGS
#define TOML_POP_WARNINGS
#endif
#ifndef TOML_INTERFACE
#define TOML_INTERFACE
#endif
#ifndef TOML_EMPTY_BASES
#define TOML_EMPTY_BASES
#endif
#ifndef TOML_ALWAYS_INLINE
#define TOML_ALWAYS_INLINE inline
#endif
#ifndef TOML_ASSUME
#define TOML_ASSUME(cond) (void)0
#endif
#ifndef TOML_UNREACHABLE
#define TOML_UNREACHABLE (void)0
#endif
#define TOML_NO_DEFAULT_CASE default: TOML_UNREACHABLE
#ifdef __cpp_consteval
#define TOML_CONSTEVAL consteval
#else
#define TOML_CONSTEVAL constexpr
#endif
#ifndef __INTELLISENSE__
#if __has_cpp_attribute(likely)
#define TOML_LIKELY [[likely]]
#endif
#if __has_cpp_attribute(unlikely)
#define TOML_UNLIKELY [[unlikely]]
#endif
#if __has_cpp_attribute(no_unique_address)
#define TOML_NO_UNIQUE_ADDRESS [[no_unique_address]]
#endif
#if __has_cpp_attribute(nodiscard) >= 201907L
#define TOML_NODISCARD_CTOR [[nodiscard]]
#endif
#endif //__INTELLISENSE__
#ifndef TOML_LIKELY
#define TOML_LIKELY
#endif
#ifndef TOML_UNLIKELY
#define TOML_UNLIKELY
#endif
#ifndef TOML_NO_UNIQUE_ADDRESS
#define TOML_NO_UNIQUE_ADDRESS
#endif
#ifndef TOML_NODISCARD_CTOR
#define TOML_NODISCARD_CTOR
#endif
#define TOML_LANG_MAJOR 0
#define TOML_LANG_MINOR 5
#define TOML_LANG_REVISION 0
#define TOML_LANG_MAKE_VERSION(maj, min, rev) \
((maj) * 1000 + (min) * 25 + (rev))
#if TOML_UNRELEASED_FEATURES
#define TOML_LANG_EFFECTIVE_VERSION \
TOML_LANG_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION+1)
#else
#define TOML_LANG_EFFECTIVE_VERSION \
TOML_LANG_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION)
#endif
#define TOML_LANG_HIGHER_THAN(maj, min, rev) \
(TOML_LANG_EFFECTIVE_VERSION > TOML_LANG_MAKE_VERSION(maj, min, rev))
#define TOML_LANG_AT_LEAST(maj, min, rev) \
(TOML_LANG_EFFECTIVE_VERSION >= TOML_LANG_MAKE_VERSION(maj, min, rev))
#define TOML_LANG_EXACTLY(maj, min, rev) \
(TOML_LANG_EFFECTIVE_VERSION == TOML_LANG_MAKE_VERSION(maj, min, rev))
////////// INCLUDES
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
#include <cstdint>
#include <cstring> //memcpy, memset
#include <cmath> //log10
#include <optional>
#include <memory>
#include <string_view>
#include <string>
#include <vector>
#include <map>
#include <iosfwd>
#include <charconv>
#if TOML_USE_STREAMS_FOR_FLOATS
#include <sstream>
#endif
#if TOML_EXCEPTIONS
#include <stdexcept>
#endif
TOML_POP_WARNINGS
#if TOML_CHAR_8_STRINGS
#if !defined(__cpp_lib_char8_t)
#error toml++ requires implementation support to use char8_t strings, but yours does not provide it.
#endif
#define TOML_STRING_PREFIX_1(S) u8##S
#define TOML_STRING_PREFIX(S) TOML_STRING_PREFIX_1(S)
#else
#define TOML_STRING_PREFIX(S) S
#endif
////////// FORWARD DECLARATIONS & TYPEDEFS
// clang-format on
namespace toml
{
inline namespace literals
{
using namespace std::string_literals;
using namespace std::string_view_literals;
[[nodiscard]] TOML_ALWAYS_INLINE
TOML_CONSTEVAL uint8_t operator"" _u8(unsigned long long n) noexcept
{
return static_cast<uint8_t>(n);
}
[[nodiscard]] TOML_ALWAYS_INLINE
TOML_CONSTEVAL size_t operator"" _sz(unsigned long long n) noexcept
{
return static_cast<size_t>(n);
}
}
struct date final
{
uint16_t year;
uint8_t month;
uint8_t day;
[[nodiscard]]
friend bool operator == (date lhs, date rhs) noexcept
{
return lhs.year == rhs.year
&& lhs.month == rhs.month
&& lhs.day == rhs.day;
}
[[nodiscard]]
friend bool operator != (date lhs, date rhs) noexcept
{
return lhs.year != rhs.year
|| lhs.month != rhs.month
|| lhs.day != rhs.day;
}
};
struct time final
{
uint8_t hour;
uint8_t minute;
uint8_t second;
uint32_t nanosecond;
[[nodiscard]]
friend bool operator == (time lhs, time rhs) noexcept
{
return lhs.hour == rhs.hour
&& lhs.minute == rhs.minute
&& lhs.second == rhs.second
&& lhs.nanosecond == rhs.nanosecond;
}
[[nodiscard]]
friend bool operator != (time lhs, time rhs) noexcept
{
return lhs.hour != rhs.hour
|| lhs.minute != rhs.minute
|| lhs.second != rhs.second
|| lhs.nanosecond != rhs.nanosecond;
}
};
struct time_offset final
{
int8_t hours;
int8_t minutes;
[[nodiscard]]
friend bool operator == (time_offset lhs, time_offset rhs) noexcept
{
return lhs.hours == rhs.hours
&& lhs.minutes == rhs.minutes;
}
[[nodiscard]]
friend bool operator != (time_offset lhs, time_offset rhs) noexcept
{
return lhs.hours != rhs.hours
|| lhs.minutes != rhs.minutes;
}
};
struct date_time final
{
toml::date date;
toml::time time;
std::optional<toml::time_offset> time_offset;
[[nodiscard]]
friend bool operator == (const date_time& lhs, const date_time& rhs) noexcept
{
return lhs.date == rhs.date
&& lhs.time == rhs.time
&& lhs.time_offset == rhs.time_offset;
}
[[nodiscard]]
friend bool operator != (const date_time& lhs, const date_time& rhs) noexcept
{
return lhs.date != rhs.date
|| lhs.time != rhs.time
|| lhs.time_offset != rhs.time_offset;
}
};
#if TOML_CHAR_8_STRINGS
using string_char = char8_t;
using string = std::u8string;
using string_view = std::u8string_view;
#else
using string_char = char;
using string = std::string;
using string_view = std::string_view;
#endif
template <typename T>
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
class node;
template <typename T>
class node_view;
template <typename T>
class value;
class array;
class table;
class default_formatter;
namespace impl
{
#if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20))
template <typename T>
using remove_cvref_t = std::remove_cvref_t<T>;
#else
template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
#endif
class parser;
template <typename T>
inline constexpr bool is_value =
std::is_same_v<T, string>
|| std::is_same_v<T, int64_t>
|| std::is_same_v<T, double>
|| std::is_same_v<T, bool>
|| std::is_same_v<T, date>
|| std::is_same_v<T, time>
|| std::is_same_v<T, date_time>;
template <typename T>
inline constexpr bool is_value_or_promotable =
is_value<T>
|| std::is_same_v<T, string_view>
|| std::is_same_v<T, int32_t>
|| std::is_same_v<T, int16_t>
|| std::is_same_v<T, int8_t>
|| std::is_same_v<T, uint32_t>
|| std::is_same_v<T, uint16_t>
|| std::is_same_v<T, uint8_t>
|| std::is_same_v<T, float>;
template <typename T>
inline constexpr bool is_value_or_node =
is_value<T>
|| std::is_same_v<T, array>
|| std::is_same_v<T, table>;
template <typename T> struct node_wrapper { using type = T; };
template <> struct node_wrapper<string> { using type = value<string>; };
template <> struct node_wrapper<int64_t> { using type = value<int64_t>; };
template <> struct node_wrapper<double> { using type = value<double>; };
template <> struct node_wrapper<bool> { using type = value<bool>; };
template <> struct node_wrapper<date> { using type = value<date>; };
template <> struct node_wrapper<time> { using type = value<time>; };
template <> struct node_wrapper<date_time> { using type = value<date_time>; };
template <typename T> struct value_promoter { using type = T; };
template <> struct value_promoter<string_view> { using type = string; };
template <> struct value_promoter<int32_t> { using type = int64_t; };
template <> struct value_promoter<int16_t> { using type = int64_t; };
template <> struct value_promoter<int8_t> { using type = int64_t; };
template <> struct value_promoter<uint32_t> { using type = int64_t; };
template <> struct value_promoter<uint16_t> { using type = int64_t; };
template <> struct value_promoter<uint8_t> { using type = int64_t; };
template <> struct value_promoter<float> { using type = double; };
template <typename T>
std::optional<size_t> find(const std::vector<T>& haystack, const T& needle) noexcept
{
// Q: "why not use std::find??"
// A: Because <algorithm> is _huge_ and std::find would be the only thing I used from it.
// I don't want to impose such a heavy burden on users.
const auto end = haystack.size();
for (size_t i = 0; i < end; i++)
if (haystack[i] == needle)
return i;
return {};
}
}
template <typename T>
using node_of = typename impl::node_wrapper<T>::type;
template <typename T>
using value_of = typename impl::value_promoter<T>::type;
struct source_position
{
uint32_t line; //begins at 1
uint32_t column; //begins at 1
[[nodiscard]]
friend bool operator == (const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line == rhs.line
&& lhs.column == rhs.column;
}
[[nodiscard]]
friend bool operator != (const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line != rhs.line
|| lhs.column != rhs.column;
}
[[nodiscard]]
friend bool operator < (const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line < rhs.line
|| (lhs.line == rhs.line && lhs.column < rhs.column);
}
[[nodiscard]]
friend bool operator <= (const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line < rhs.line
|| (lhs.line == rhs.line && lhs.column <= rhs.column);
}
};
struct source_region
{
source_position begin;
source_position end;
std::shared_ptr<const std::string> path;
};
enum class node_type : uint8_t
{
table,
array,
string,
integer,
floating_point,
boolean,
date,
time,
date_time
};
TOML_PUSH_WARNINGS
TOML_DISABLE_FIELD_INIT_WARNING
#if TOML_EXCEPTIONS
class parse_error final
: public std::runtime_error
{
private:
source_region rgn;
public:
TOML_NODISCARD_CTOR
parse_error(const char* description, source_region&& region) noexcept
: std::runtime_error{ description },
rgn{ std::move(region) }
{}
TOML_NODISCARD_CTOR
parse_error(const char* description, const source_region& region) noexcept
: std::runtime_error{ description },
rgn{ region }
{}
TOML_NODISCARD_CTOR
parse_error(const char* description, const source_position& position, const std::shared_ptr<const std::string>& source_path) noexcept
: std::runtime_error{ description },
rgn{ position, position, source_path }
{}
TOML_NODISCARD_CTOR
parse_error(const char* description, const source_position& position) noexcept
: std::runtime_error{ description },
rgn{ position, position }
{}
[[nodiscard]]
const source_region& where() const noexcept
{
return rgn;
}
};
#else
struct parse_error final
{
std::string what;
source_region where;
TOML_NODISCARD_CTOR
parse_error() noexcept = default;
TOML_NODISCARD_CTOR
parse_error(const char* description, source_region&& region) noexcept
: what{ description },
where{ std::move(region) }
{}
TOML_NODISCARD_CTOR
parse_error(const char* description, const source_region& region) noexcept
: what{ description },
where{ region }
{}
TOML_NODISCARD_CTOR
parse_error(const char* description, const source_position& position, const std::shared_ptr<const std::string>& source_path) noexcept
: what{ description },
where{ position, position, source_path }
{}
TOML_NODISCARD_CTOR
parse_error(const char* description, const source_position& position) noexcept
: what{ description },
where{ position, position }
{}
};
#endif
TOML_POP_WARNINGS
}

View File

@ -0,0 +1,717 @@
#pragma once
#include "toml_utf8.h"
#include "toml_value.h"
#include "toml_array.h"
namespace toml::impl
{
struct TOML_INTERFACE formatter_writer_interface
{
virtual void operator() (const void*, size_t) const TOML_MAY_THROW = 0;
virtual void operator() (char) const TOML_MAY_THROW = 0;
virtual ~formatter_writer_interface() noexcept = default;
};
template <typename T>
class formatter_writer;
template <typename CHAR>
class TOML_EMPTY_BASES formatter_writer<std::basic_ostream<CHAR>> : public formatter_writer_interface
{
private:
std::basic_ostream<CHAR>& target;
public:
void operator() (const void* data, size_t size) const TOML_MAY_THROW override
{
TOML_ASSERT(data && size);
target.write(reinterpret_cast<const CHAR*>(data), static_cast<std::streamsize>(size));
}
void operator() (char character) const TOML_MAY_THROW override
{
target.put(static_cast<CHAR>(character));
}
formatter_writer(std::basic_ostream<CHAR>& target_) noexcept
: target{ target_ }
{}
};
template <typename CHAR>
formatter_writer(std::basic_ostream<CHAR>&) -> formatter_writer<std::basic_ostream<CHAR>>;
}
namespace toml
{
class default_formatter final
{
private:
const toml::table& source;
std::string_view indent_string;
size_t indent_string_columns = {};
mutable int indent_level;
mutable bool naked_newline;
mutable std::vector<toml::string> key_path;
mutable const impl::formatter_writer_interface* writer = nullptr;
TOML_ALWAYS_INLINE
void write(char character) const TOML_MAY_THROW
{
(*writer)(character);
}
template <typename CHAR>
TOML_ALWAYS_INLINE
void write(std::basic_string_view<CHAR> strv) const TOML_MAY_THROW
{
static_assert(sizeof(CHAR) == 1_sz);
(*writer)(reinterpret_cast<const uint8_t*>(strv.data()), strv.length());
}
template <typename CHAR>
TOML_ALWAYS_INLINE
void write(const std::basic_string<CHAR>& str) const TOML_MAY_THROW
{
static_assert(sizeof(CHAR) == 1_sz);
(*writer)(reinterpret_cast<const uint8_t*>(str.data()), str.length());
}
void write_newline(bool force = false) const TOML_MAY_THROW
{
if (!naked_newline || force)
{
write('\n');
naked_newline = true;
}
}
void write_indent() const TOML_MAY_THROW
{
for (int i = 0; i < indent_level; i++)
{
write(indent_string);
naked_newline = false;
}
}
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS // some compilers will complain about a tautological unsigned >= 0.
// TINAE - char can have signed _or_ unsigned semantics and I can't
// be arsed handling this differently
static toml::string_view escape_string_character(const toml::string_char& c) noexcept
{
if (c >= toml::string_char{} && c <= TOML_STRING_PREFIX('\x1F')) TOML_UNLIKELY
{
switch (c)
{
case TOML_STRING_PREFIX('\x00'): return TOML_STRING_PREFIX("\\u0000"sv);
case TOML_STRING_PREFIX('\x01'): return TOML_STRING_PREFIX("\\u0001"sv);
case TOML_STRING_PREFIX('\x02'): return TOML_STRING_PREFIX("\\u0002"sv);
case TOML_STRING_PREFIX('\x03'): return TOML_STRING_PREFIX("\\u0003"sv);
case TOML_STRING_PREFIX('\x04'): return TOML_STRING_PREFIX("\\u0004"sv);
case TOML_STRING_PREFIX('\x05'): return TOML_STRING_PREFIX("\\u0005"sv);
case TOML_STRING_PREFIX('\x06'): return TOML_STRING_PREFIX("\\u0006"sv);
case TOML_STRING_PREFIX('\x07'): return TOML_STRING_PREFIX("\\u0007"sv);
case TOML_STRING_PREFIX('\x08'): return TOML_STRING_PREFIX("\\b"sv);
case TOML_STRING_PREFIX('\x09'): return TOML_STRING_PREFIX("\\t"sv);
case TOML_STRING_PREFIX('\x0A'): return TOML_STRING_PREFIX("\\n"sv);
case TOML_STRING_PREFIX('\x0B'): return TOML_STRING_PREFIX("\\u000B"sv);
case TOML_STRING_PREFIX('\x0C'): return TOML_STRING_PREFIX("\\f"sv);
case TOML_STRING_PREFIX('\x0D'): return TOML_STRING_PREFIX("\\r"sv);
case TOML_STRING_PREFIX('\x0E'): return TOML_STRING_PREFIX("\\u000E"sv);
case TOML_STRING_PREFIX('\x0F'): return TOML_STRING_PREFIX("\\u000F"sv);
case TOML_STRING_PREFIX('\x10'): return TOML_STRING_PREFIX("\\u0010"sv);
case TOML_STRING_PREFIX('\x11'): return TOML_STRING_PREFIX("\\u0011"sv);
case TOML_STRING_PREFIX('\x12'): return TOML_STRING_PREFIX("\\u0012"sv);
case TOML_STRING_PREFIX('\x13'): return TOML_STRING_PREFIX("\\u0013"sv);
case TOML_STRING_PREFIX('\x14'): return TOML_STRING_PREFIX("\\u0014"sv);
case TOML_STRING_PREFIX('\x15'): return TOML_STRING_PREFIX("\\u0015"sv);
case TOML_STRING_PREFIX('\x16'): return TOML_STRING_PREFIX("\\u0016"sv);
case TOML_STRING_PREFIX('\x17'): return TOML_STRING_PREFIX("\\u0017"sv);
case TOML_STRING_PREFIX('\x18'): return TOML_STRING_PREFIX("\\u0018"sv);
case TOML_STRING_PREFIX('\x19'): return TOML_STRING_PREFIX("\\u0019"sv);
case TOML_STRING_PREFIX('\x1A'): return TOML_STRING_PREFIX("\\u001A"sv);
case TOML_STRING_PREFIX('\x1B'): return TOML_STRING_PREFIX("\\u001B"sv);
case TOML_STRING_PREFIX('\x1C'): return TOML_STRING_PREFIX("\\u001C"sv);
case TOML_STRING_PREFIX('\x1D'): return TOML_STRING_PREFIX("\\u001D"sv);
case TOML_STRING_PREFIX('\x1E'): return TOML_STRING_PREFIX("\\u001E"sv);
case TOML_STRING_PREFIX('\x1F'): return TOML_STRING_PREFIX("\\u001F"sv);
TOML_NO_DEFAULT_CASE;
}
}
else if (c == TOML_STRING_PREFIX('\x7F')) TOML_UNLIKELY
return TOML_STRING_PREFIX("\\u007F"sv);
else if (c == TOML_STRING_PREFIX('"')) TOML_UNLIKELY
return TOML_STRING_PREFIX("\\\""sv);
else
return toml::string_view{ &c, 1_sz };
}
TOML_POP_WARNINGS
static toml::string make_key_segment(const toml::string& str) noexcept
{
if (str.empty())
return TOML_STRING_PREFIX("''"s);
else
{
bool requiresQuotes = false;
{
impl::utf8_decoder decoder;
for (size_t i = 0; i < str.length() && !requiresQuotes; i++)
{
decoder(static_cast<uint8_t>(str[i]));
if (decoder.error())
requiresQuotes = true;
else if (decoder.has_code_point())
requiresQuotes = !impl::is_bare_key_character(decoder.codepoint);
}
}
if (requiresQuotes)
{
toml::string s;
s.reserve(str.length() + 2_sz);
s += TOML_STRING_PREFIX('"');
for (auto c : str)
s.append(escape_string_character(c));
s += TOML_STRING_PREFIX('"');
return s;
}
else
return str;
}
}
void write_key_segment(const toml::string& str) const TOML_MAY_THROW
{
if (str.empty())
write("''"sv);
else
{
bool requiresQuotes = false;
{
impl::utf8_decoder decoder;
for (size_t i = 0; i < str.length() && !requiresQuotes; i++)
{
decoder(static_cast<uint8_t>(str[i]));
if (decoder.error())
requiresQuotes = true;
else if (decoder.has_code_point())
requiresQuotes = !impl::is_bare_key_character(decoder.codepoint);
}
}
if (requiresQuotes)
{
write('"');
for (auto c : str)
write(escape_string_character(c));
write('"');
}
else
write(str);
}
}
void write_key_path() const TOML_MAY_THROW
{
for (const auto& segment : key_path)
{
if (std::addressof(segment) > key_path.data())
write('.');
write(segment);
}
naked_newline = false;
}
void write(const value<toml::string>& val) const TOML_MAY_THROW
{
const auto& str = val.get();
if (str.empty())
write("''"sv);
else
{
write('"');
for (auto c : str)
write(escape_string_character(c));
write('"');
}
naked_newline = false;
}
template <typename T>
void write_integer(T val) const TOML_MAY_THROW
{
char buf[20_sz]; //strlen("-9223372036854775808")
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
(*writer)(buf, static_cast<size_t>(res.ptr - buf));
naked_newline = false;
}
void write(const value<int64_t>& val) const TOML_MAY_THROW
{
write_integer(val.get());
}
void write(const value<double>& val) const TOML_MAY_THROW
{
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::ostringstream oss;
oss << val.get();
write(oss.str());
if (val.get() == 0.0)
write(".0"sv);
}
#else
{
char buf[32_sz];
const auto res = std::to_chars(buf, buf + sizeof(buf), val.get());
const auto sv = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
write(sv);
bool needs_decimal_point = true;
for (auto ch : sv)
{
if (ch == 'e' || ch == 'E' || ch == '.')
{
needs_decimal_point = false;
break;
}
}
if (needs_decimal_point)
write(".0"sv);
}
#endif
naked_newline = false;
}
void write(const value<bool>& val) const TOML_MAY_THROW
{
write(val.get() ? "true"sv : "false"sv);
naked_newline = false;
}
template <typename T>
void write_zero_padded_integer(T intval, size_t digits) const TOML_MAY_THROW
{
static_assert(std::is_unsigned_v<T>);
char buf[17_sz]; //strlen("9223372036854775807")
const auto res = std::to_chars(buf, buf + sizeof(buf), intval);
const auto len = static_cast<size_t>(res.ptr - buf);
for (size_t i = len; i < digits; i++)
write('0');
(*writer)(buf, len);
naked_newline = false;
}
void write(const time& tm) const TOML_MAY_THROW
{
write_zero_padded_integer(tm.hour, 2_sz);
write(':');
write_zero_padded_integer(tm.minute, 2_sz);
write(':');
write_zero_padded_integer(tm.second, 2_sz);
if (tm.nanosecond && tm.nanosecond <= 999999999u)
{
write('.');
auto ns = tm.nanosecond;
size_t digits = 9_sz;
while (ns % 10u == 0u)
{
ns /= 10u;
digits--;
}
write_integer(ns);
}
}
void write(const date& dt) const TOML_MAY_THROW
{
write_zero_padded_integer(dt.year, 4_sz);
write('-');
write_zero_padded_integer(dt.month, 2_sz);
write('-');
write_zero_padded_integer(dt.day, 2_sz);
}
void write(const date_time& dt) const TOML_MAY_THROW
{
write(dt.date);
write('T');
write(dt.time);
if (dt.time_offset)
{
const auto& to = *dt.time_offset;
if (!to.hours && !to.minutes)
write('Z');
else
{
write(to.hours < 0 || to.minutes < 0 ? '-' : '+');
write_zero_padded_integer(static_cast<uint8_t>(to.hours < 0 ? -to.hours : to.hours), 2_sz);
write(':');
write_zero_padded_integer(static_cast<uint8_t>(to.minutes < 0 ? -to.minutes : to.minutes), 2_sz);
}
}
}
void write(const value<time>& val) const TOML_MAY_THROW
{
write(val.get());
}
void write(const value<date>& val) const TOML_MAY_THROW
{
write(val.get());
}
void write(const value<date_time>& val) const TOML_MAY_THROW
{
write(val.get());
}
inline void write_inline(const table& /*tab*/) const TOML_MAY_THROW;
static size_t inline_columns(const node& node) noexcept
{
switch (node.type())
{
case node_type::table: //assumed to be inline
{
auto& values = reinterpret_cast<const table*>(&node)->values;
if (values.empty())
return 2_sz; // "{}"
size_t weight = 3_sz; // "{ }"
for (auto& [k, v] : values)
weight += k.length() + inline_columns(*v) + 2_sz; // + ", "
return weight;
}
case node_type::array:
{
auto& values = reinterpret_cast<const array*>(&node)->values;
if (values.empty())
return 2_sz; // "[]"
size_t weight = 3_sz; // "[ ]"
for (auto& v : values)
weight += inline_columns(*v) + 2_sz; // + ", "
return weight;
}
case node_type::string:
return reinterpret_cast<const value<string>*>(&node)->get().length() + 2_sz; // + ""
case node_type::integer:
{
auto v = reinterpret_cast<const value<int64_t>*>(&node)->get();
if (!v)
return 1_sz;
size_t weight = {};
if (v < 0)
{
weight += 1;
v *= -1;
}
return weight + static_cast<size_t>(std::log10(static_cast<double>(v)));
}
case node_type::floating_point:
{
auto v = reinterpret_cast<const value<double>*>(&node)->get();
if (v == 0.0)
return 3_sz;
size_t weight = 2_sz; // ".0"
if (v < 0.0)
{
weight += 1;
v *= -1.0;
}
return weight + static_cast<size_t>(std::log10(v));
}
case node_type::boolean: return 5_sz;
case node_type::date: [[fallthrough]];
case node_type::time: return 10_sz;
case node_type::date_time: return 30_sz;
TOML_NO_DEFAULT_CASE;
}
}
static bool forces_multiline(const node& node, size_t starting_column_bias = 0) noexcept
{
return (inline_columns(node) + starting_column_bias) > 100_sz;
}
void write(const array& arr) const TOML_MAY_THROW
{
if (arr.values.empty())
write("[]"sv);
else
{
const auto multiline = forces_multiline(
arr,
indent_string_columns * static_cast<size_t>(indent_level < 0 ? 0 : indent_level)
);
const auto original_indent = indent_level;
write("["sv);
if (multiline)
{
if (indent_level < 0)
indent_level++;
indent_level++;
}
else
write(' ');
for (auto& v : arr.values)
{
if (std::addressof(v) > arr.values.data())
{
write(',');
if (!multiline)
write(' ');
}
if (multiline)
{
write_newline(true);
write_indent();
}
const auto type = v->type();
switch (type)
{
case node_type::table: write_inline(*reinterpret_cast<const table*>(v.get())); break;
case node_type::array: write(*reinterpret_cast<const array*>(v.get())); break;
case node_type::string: write(*reinterpret_cast<const value<string>*>(v.get())); break;
case node_type::integer: write(*reinterpret_cast<const value<int64_t>*>(v.get())); break;
case node_type::floating_point: write(*reinterpret_cast<const value<double>*>(v.get())); break;
case node_type::boolean: write(*reinterpret_cast<const value<bool>*>(v.get())); break;
case node_type::date: write(*reinterpret_cast<const value<date>*>(v.get())); break;
case node_type::time: write(*reinterpret_cast<const value<time>*>(v.get())); break;
case node_type::date_time: write(*reinterpret_cast<const value<date_time>*>(v.get())); break;
TOML_NO_DEFAULT_CASE;
}
}
if (multiline)
{
indent_level = original_indent;
write_newline(true);
write_indent();
}
else
write(' ');
write("]"sv);
}
naked_newline = false;
}
void write(const table& tab) const TOML_MAY_THROW
{
//values, arrays, and inline tables
for (auto& [k, v] : tab.values)
{
const auto type = v->type();
if ((type == node_type::table && !reinterpret_cast<const table*>(v.get())->is_inline())
|| (type == node_type::array && reinterpret_cast<const array*>(v.get())->is_array_of_tables()))
continue;
write_newline();
write_indent();
write_key_segment(k);
write(" = "sv);
switch (type)
{
case node_type::table: write_inline(*reinterpret_cast<const table*>(v.get())); break;
case node_type::array: write(*reinterpret_cast<const array*>(v.get())); break;
case node_type::string: write(*reinterpret_cast<const value<string>*>(v.get())); break;
case node_type::integer: write(*reinterpret_cast<const value<int64_t>*>(v.get())); break;
case node_type::floating_point: write(*reinterpret_cast<const value<double>*>(v.get())); break;
case node_type::boolean: write(*reinterpret_cast<const value<bool>*>(v.get())); break;
case node_type::date: write(*reinterpret_cast<const value<date>*>(v.get())); break;
case node_type::time: write(*reinterpret_cast<const value<time>*>(v.get())); break;
case node_type::date_time: write(*reinterpret_cast<const value<date_time>*>(v.get())); break;
TOML_NO_DEFAULT_CASE;
}
}
//non-inline tables
for (auto& [k, v] : tab.values)
{
const auto type = v->type();
if (type != node_type::table || reinterpret_cast<const table*>(v.get())->is_inline())
continue;
auto& child_tab = *reinterpret_cast<const table*>(v.get());
//we can skip indenting and emitting the headers for tables that only contain other tables
//(so we don't over-nest)
size_t child_value_count{}; //includes inline tables and non-table arrays
size_t child_table_count{};
size_t child_table_array_count{};
for (auto& [child_k, child_v] : child_tab.values)
{
const auto child_type = child_v->type();
switch (child_type)
{
case node_type::table:
if (reinterpret_cast<const table*>(child_v.get())->is_inline())
child_value_count++;
else
child_table_count++;
break;
case node_type::array:
if (reinterpret_cast<const array*>(child_v.get())->is_array_of_tables())
child_table_array_count++;
else
child_value_count++;
break;
default:
child_value_count++;
}
}
bool skip_self = false;
if (child_value_count == 0_sz && (child_table_count > 0_sz || child_table_array_count > 0_sz))
skip_self = true;
if (!skip_self)
indent_level++;
key_path.push_back(make_key_segment(k));
if (!skip_self)
{
write_newline();
write_newline(true);
write_indent();
write("["sv);
write_key_path();
write("]"sv);
write_newline(true);
}
write(child_tab);
key_path.pop_back();
if (!skip_self)
indent_level--;
}
//table arrays
for (auto& [k, v] : tab.values)
{
const auto type = v->type();
if (type != node_type::array || !reinterpret_cast<const array*>(v.get())->is_array_of_tables())
continue;
auto& node = *reinterpret_cast<const array*>(v.get());
indent_level++;
key_path.push_back(make_key_segment(k));
for (auto& t : node.values)
{
write_newline();
write_newline(true);
write_indent();
write("[["sv);
write_key_path();
write("]]"sv);
write_newline(true);
write(*reinterpret_cast<const table*>(t.get()));
}
key_path.pop_back();
indent_level--;
}
}
public:
explicit default_formatter(const toml::table& source_, std::string_view indent_string_ = " "sv) noexcept
: source{ source_ },
indent_string{ indent_string_ }
{
for (auto c : indent_string)
indent_string_columns += c == '\t' ? 4_sz : 1_sz;
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const default_formatter& rhs) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
"The stream's underlying character type must be 1 byte in size."
);
rhs.indent_level = -1;
rhs.naked_newline = true;
rhs.key_path.clear();
auto fw = impl::formatter_writer{ lhs };
rhs.writer = &fw;
rhs.write(rhs.source);
return lhs;
}
};
inline void default_formatter::write_inline(const toml::table& tab) const TOML_MAY_THROW
{
if (tab.values.empty())
write("{}"sv);
else
{
write("{ "sv);
bool first = false;
for (auto& [k, v] : tab.values)
{
if (first)
{
write(", "sv);
}
first = true;
write_key_segment(k);
write(" = "sv);
const auto type = v->type();
switch (type)
{
case node_type::table: write_inline(*reinterpret_cast<const table*>(v.get())); break;
case node_type::array: write(*reinterpret_cast<const array*>(v.get())); break;
case node_type::string: write(*reinterpret_cast<const value<string>*>(v.get())); break;
case node_type::integer: write(*reinterpret_cast<const value<int64_t>*>(v.get())); break;
case node_type::floating_point: write(*reinterpret_cast<const value<double>*>(v.get())); break;
case node_type::boolean: write(*reinterpret_cast<const value<bool>*>(v.get())); break;
case node_type::date: write(*reinterpret_cast<const value<date>*>(v.get())); break;
case node_type::time: write(*reinterpret_cast<const value<time>*>(v.get())); break;
case node_type::date_time: write(*reinterpret_cast<const value<date_time>*>(v.get())); break;
TOML_NO_DEFAULT_CASE;
}
}
write(" }"sv);
}
naked_newline = false;
}
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const table& rhs) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
"The stream's underlying character type must be 1 byte in size."
);
return lhs << default_formatter{ rhs };
}
}

132
include/toml++/toml_node.h Normal file
View File

@ -0,0 +1,132 @@
#pragma once
#include "toml_common.h"
namespace toml
{
class TOML_INTERFACE node
{
private:
friend class impl::parser;
source_region rgn{};
protected:
node(node&& other) noexcept
: rgn{ std::move(other.rgn) }
{}
node& operator= (node&& rhs) noexcept
{
rgn = std::move(rhs.rgn);
return *this;
}
public:
node() noexcept = default;
node(const node&) = delete;
node& operator= (const node&) = delete;
virtual ~node() noexcept = default;
[[nodiscard]] virtual bool is_value() const noexcept { return false; }
[[nodiscard]] virtual bool is_string() const noexcept { return false; }
[[nodiscard]] virtual bool is_integer() const noexcept { return false; }
[[nodiscard]] virtual bool is_floating_point() const noexcept { return false; }
[[nodiscard]] virtual bool is_boolean() const noexcept { return false; }
[[nodiscard]] virtual bool is_date() const noexcept { return false; }
[[nodiscard]] virtual bool is_time() const noexcept { return false; }
[[nodiscard]] virtual bool is_date_time() const noexcept { return false; }
[[nodiscard]] virtual bool is_array() const noexcept { return false; }
[[nodiscard]] virtual bool is_table() const noexcept { return false; }
[[nodiscard]] virtual bool is_array_of_tables() const noexcept { return false; }
template <typename T>
[[nodiscard]] bool is() const noexcept
{
using type = T;
static_assert(
impl::is_value_or_node<type>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
if constexpr (std::is_same_v<type, string>) return is_string();
else if constexpr (std::is_same_v<type, int64_t>) return is_integer();
else if constexpr (std::is_same_v<type, double>) return is_floating_point();
else if constexpr (std::is_same_v<type, bool>) return is_boolean();
else if constexpr (std::is_same_v<type, date>) return is_date();
else if constexpr (std::is_same_v<type, time>) return is_time();
else if constexpr (std::is_same_v<type, date_time>) return is_date_time();
else if constexpr (std::is_same_v<type, array>) return is_array();
else if constexpr (std::is_same_v<type, table>) return is_table();
}
[[nodiscard]] virtual value<string>* as_string() noexcept { return nullptr; }
[[nodiscard]] virtual value<int64_t>* as_integer() noexcept { return nullptr; }
[[nodiscard]] virtual value<double>* as_floating_point() noexcept { return nullptr; }
[[nodiscard]] virtual value<bool>* as_boolean() noexcept { return nullptr; }
[[nodiscard]] virtual value<date>* as_date() noexcept { return nullptr; }
[[nodiscard]] virtual value<time>* as_time() noexcept { return nullptr; }
[[nodiscard]] virtual value<date_time>* as_date_time() noexcept { return nullptr; }
[[nodiscard]] virtual array* as_array() noexcept { return nullptr; }
[[nodiscard]] virtual table* as_table() noexcept { return nullptr; }
[[nodiscard]] virtual const value<string>* as_string() const noexcept { return nullptr; }
[[nodiscard]] virtual const value<int64_t>* as_integer() const noexcept { return nullptr; }
[[nodiscard]] virtual const value<double>* as_floating_point() const noexcept { return nullptr; }
[[nodiscard]] virtual const value<bool>* as_boolean() const noexcept { return nullptr; }
[[nodiscard]] virtual const value<date>* as_date() const noexcept { return nullptr; }
[[nodiscard]] virtual const value<time>* as_time() const noexcept { return nullptr; }
[[nodiscard]] virtual const value<date_time>* as_date_time() const noexcept { return nullptr; }
[[nodiscard]] virtual const array* as_array() const noexcept { return nullptr; }
[[nodiscard]] virtual const table* as_table() const noexcept { return nullptr; }
template <typename T>
[[nodiscard]] node_of<T>* as() noexcept
{
using type = T;
static_assert(
impl::is_value_or_node<type>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
if constexpr (std::is_same_v<type, string>) return as_string();
else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
else if constexpr (std::is_same_v<type, double>) return as_floating_point();
else if constexpr (std::is_same_v<type, bool>) return as_boolean();
else if constexpr (std::is_same_v<type, date>) return as_date();
else if constexpr (std::is_same_v<type, time>) return as_time();
else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
else if constexpr (std::is_same_v<type, array>) return as_array();
else if constexpr (std::is_same_v<type, table>) return as_table();
}
template <typename T>
[[nodiscard]] const node_of<T>* as() const noexcept
{
using type = T;
static_assert(
impl::is_value_or_node<type>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
if constexpr (std::is_same_v<type, string>) return as_string();
else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
else if constexpr (std::is_same_v<type, double>) return as_floating_point();
else if constexpr (std::is_same_v<type, bool>) return as_boolean();
else if constexpr (std::is_same_v<type, date>) return as_date();
else if constexpr (std::is_same_v<type, time>) return as_time();
else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
else if constexpr (std::is_same_v<type, array>) return as_array();
else if constexpr (std::is_same_v<type, table>) return as_table();
}
[[nodiscard]] virtual node_type type() const noexcept = 0;
[[nodiscard]]
const source_region& region() const noexcept
{
return rgn;
}
};
}

View File

@ -0,0 +1,312 @@
#pragma once
#include "toml_table.h"
#include "toml_array.h"
#include "toml_value.h"
namespace toml::impl
{
template <typename T>
struct node_view_traits;
template <>
struct node_view_traits<const table>
{
using member_type = const table*;
using key_type = string_view;
[[nodiscard]]
static const node* get(const table* tbl, key_type key) noexcept
{
return tbl->get(key);
}
template <typename U>
[[nodiscard]]
static const node_of<U>* as(const table* tbl, key_type key) noexcept
{
return tbl->get_as<U>(key);
}
};
template <>
struct node_view_traits<table>
{
using member_type = table*;
using key_type = string_view;
[[nodiscard]]
static node* get(table* tbl, key_type key) noexcept
{
return tbl->get(key);
}
[[nodiscard]]
static const node* get(const table* tbl, key_type key) noexcept
{
return tbl->get(key);
}
template <typename T>
[[nodiscard]]
static node_of<T>* as(table* tbl, key_type key) noexcept
{
return tbl->get_as<T>(key);
}
template <typename T>
[[nodiscard]]
static const node_of<T>* as(const table* tbl, key_type key) noexcept
{
return tbl->get_as<T>(key);
}
};
template <typename T, typename K>
struct sub_view final { };
template <typename T>
struct node_view_traits<sub_view<T, string_view>>
{
using member_type = T;
using key_type = string_view;
[[nodiscard]]
static auto get(member_type& view, string_view key) noexcept
{
auto parent = view.as_table();
return parent ? parent->get(key) : nullptr;
}
[[nodiscard]]
static const node* get(const member_type& view, string_view key) noexcept
{
auto parent = view.as_table();
return parent ? parent->get(key) : nullptr;
}
template <typename U>
[[nodiscard]]
static auto as(member_type& view, string_view key) noexcept
{
auto parent = view.as_table();
return parent ? parent->template get_as<U>(key) : nullptr;
}
template <typename U>
[[nodiscard]]
static const node_of<U>* as(const member_type& view, string_view key) noexcept
{
auto parent = view.as_table();
return parent ? parent->template get_as<U>(key) : nullptr;
}
};
template <typename T>
struct node_view_traits<sub_view<T, size_t>>
{
using member_type = T;
using key_type = size_t;
[[nodiscard]]
static auto get(member_type& view, size_t index) noexcept
{
auto parent = view.as_array();
return parent ? parent->get(index) : nullptr;
}
[[nodiscard]]
static const node* get(const member_type& view, size_t index) noexcept
{
auto parent = view.as_array();
return parent ? parent->get(index) : nullptr;
}
template <typename U>
[[nodiscard]]
static auto as(member_type& view, size_t index) noexcept
{
auto parent = view.as_array();
return parent ? parent->template get_as<U>(index) : nullptr;
}
template <typename U>
[[nodiscard]]
static const node_of<U>* as(const member_type& view, size_t index) noexcept
{
auto parent = view.as_array();
return parent ? parent->template get_as<U>(index) : nullptr;
}
};
}
namespace toml
{
template <typename T>
class node_view final
{
public:
using traits = impl::node_view_traits<T>;
using key_type = typename traits::key_type;
private:
using member_type = typename traits::member_type;
member_type obj_;
key_type key_;
public:
TOML_NODISCARD_CTOR
node_view(member_type obj, key_type key) noexcept
: obj_{ obj },
key_{ key }
{}
[[nodiscard]] auto get() noexcept { return traits::get(obj_, key_); }
[[nodiscard]] const node* get() const noexcept { return traits::get(obj_, key_); }
[[nodiscard]] explicit operator bool() const noexcept { return !!get(); }
template <typename U>
[[nodiscard]]
auto as() noexcept
{
static_assert(
impl::is_value_or_node<U>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
return traits::template as<U>(obj_, key_);
}
template <typename U>
[[nodiscard]]
const node_of<U>* as() const noexcept
{
static_assert(
impl::is_value_or_node<U>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
return traits::template as<U>(obj_, key_);
}
[[nodiscard]] auto as_string() noexcept { return as<string>(); }
[[nodiscard]] auto as_integer() noexcept { return as<int64_t>(); }
[[nodiscard]] auto as_floating_point() noexcept { return as<double>(); }
[[nodiscard]] auto as_boolean() noexcept { return as<bool>(); }
[[nodiscard]] auto as_date() noexcept { return as<date>(); }
[[nodiscard]] auto as_time() noexcept { return as<time>(); }
[[nodiscard]] auto as_date_time() noexcept { return as<date_time>(); }
[[nodiscard]] auto as_array() noexcept { return as<array>(); }
[[nodiscard]] auto as_table() noexcept { return as<table>(); }
[[nodiscard]] const value<string>* as_string() const noexcept { return as<string>(); }
[[nodiscard]] const value<int64_t>* as_integer() const noexcept { return as<int64_t>(); }
[[nodiscard]] const value<double>* as_floating_point() const noexcept { return as<double>(); }
[[nodiscard]] const value<bool>* as_boolean() const noexcept { return as<bool>(); }
[[nodiscard]] const value<date>* as_date() const noexcept { return as<date>(); }
[[nodiscard]] const value<time>* as_time() const noexcept { return as<time>(); }
[[nodiscard]] const value<date_time>* as_date_time() const noexcept { return as<date_time>(); }
[[nodiscard]] const array* as_array() const noexcept { return as<array>(); }
[[nodiscard]] const table* as_table() const noexcept { return as<table>(); }
private:
template <typename U>
[[nodiscard]]
static bool value_equality(const node_view& lhs, const U& rhs) noexcept
{
const auto val = lhs.as<value_of<U>>();
return val && val->get() == rhs;
}
template <typename U>
[[nodiscard]]
static bool container_equality(const node_view& lhs, const U& rhs) noexcept
{
using elem_t = std::remove_const_t<typename U::value_type>;
static_assert(
impl::is_value_or_promotable<elem_t>,
"Container element type must be (or be convertible to) one of the basic value types"
);
const array* arr = lhs.as<array>();
if (!arr || arr->size() != rhs.size())
return false;
if (rhs.size() == 0_sz)
return true;
size_t i{};
for (auto& list_elem : rhs)
{
const auto elem = arr->get_as<value_of<elem_t>>(i++);
if (!elem || elem->get() != list_elem)
return false;
}
return true;
}
public:
[[nodiscard]] bool operator == (const string& rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (string_view rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (int64_t rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (int32_t rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (int16_t rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (int8_t rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (uint32_t rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (uint16_t rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (uint8_t rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (double rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (float rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (bool rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (const date& rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (const time& rhs) const noexcept { return value_equality(*this, rhs); }
[[nodiscard]] bool operator == (const date_time& rhs) const noexcept { return value_equality(*this, rhs); }
template <typename U>
[[nodiscard]]
bool operator == (const std::initializer_list<U>& rhs) const noexcept
{
return container_equality(*this, rhs);
}
template <typename U>
[[nodiscard]]
bool operator == (const std::vector<U>& rhs) const noexcept
{
return container_equality(*this, rhs);
}
template <typename U>
[[nodiscard]]
friend bool operator == (const U& lhs, const node_view& rhs) noexcept
{
return rhs == lhs;
}
[[nodiscard]]
node_view<impl::sub_view<node_view<T>, string_view>> operator[] (string_view key) noexcept
{
return { *this, key };
}
[[nodiscard]]
node_view<impl::sub_view<node_view<T>, size_t>> operator[] (size_t index) noexcept
{
return { *this, index };
}
};
inline node_view<table> table::operator[] (string_view key) noexcept
{
return { this, key };
}
inline node_view<const table> table::operator[] (string_view key) const noexcept
{
return { this, key };
}
}

2801
include/toml++/toml_parser.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
#pragma once
#include "toml_node.h"
namespace toml
{
class table final
: public node
{
private:
friend class impl::parser;
friend class default_formatter;
friend class node_view<table>;
string_map<std::unique_ptr<node>> values;
bool inline_ = false;
public:
TOML_NODISCARD_CTOR
table() noexcept {}
TOML_NODISCARD_CTOR
table(table&& other) noexcept
: node{ std::move(other) },
values{ std::move(other.values) },
inline_ { other.inline_ }
{}
table& operator= (table&& rhs) noexcept
{
node::operator=(std::move(rhs));
values = std::move(rhs.values);
inline_ = rhs.inline_;
return *this;
}
[[nodiscard]] bool is_table() const noexcept override { return true; }
[[nodiscard]] bool is_inline() const noexcept { return inline_; }
[[nodiscard]] table* as_table() noexcept override { return this; }
[[nodiscard]] const table* as_table() const noexcept override { return this; }
[[nodiscard]] node_type type() const noexcept override { return node_type::table; }
[[nodiscard]] size_t size() const noexcept { return values.size(); }
[[nodiscard]]
node* get(string_view key) noexcept
{
if (auto it = values.find(key); it != values.end())
return it->second.get();
return nullptr;
}
[[nodiscard]]
const node* get(string_view key) const noexcept
{
if (auto it = values.find(key); it != values.end())
return it->second.get();
return nullptr;
}
template <typename T>
[[nodiscard]]
node_of<T>* get_as(string_view key) noexcept
{
const auto node = get(key);
return node ? node->as<T>() : nullptr;
}
template <typename T>
[[nodiscard]]
const node_of<T>* get_as(string_view key) const noexcept
{
const auto node = get(key);
return node ? node->as<T>() : nullptr;
}
[[nodiscard]] inline node_view<table> operator[] (string_view) noexcept;
[[nodiscard]] inline node_view<const table> operator[] (string_view) const noexcept;
};
}

600
include/toml++/toml_utf8.h Normal file
View File

@ -0,0 +1,600 @@
#pragma once
#include "toml_common.h"
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
#include "toml_utf8_generated.h"
#endif // TOML_LANG_HIGHER_THAN(0, 5, 0)
namespace toml::impl
{
[[nodiscard]]
constexpr bool is_whitespace(char32_t codepoint) noexcept
{
// see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
// (characters that don't say "is a line-break")
return codepoint == U'\t'
|| codepoint == U' '
|| codepoint == U'\u00A0' // no-break space
|| codepoint == U'\u1680' // ogham space mark
|| (codepoint >= U'\u2000' && codepoint <= U'\u200A') // em quad -> hair space
|| codepoint == U'\u202F' // narrow no-break space
|| codepoint == U'\u205F' // medium mathematical space
|| codepoint == U'\u3000' // ideographic space
;
}
template <bool CR = true>
[[nodiscard]]
constexpr bool is_line_break(char32_t codepoint) noexcept
{
// see https://en.wikipedia.org/wiki/Whitespace_character#Unicode
// (characters that say "is a line-break")
constexpr auto low_range_end = CR ? U'\r' : U'\f';
return (codepoint >= U'\n' && codepoint <= low_range_end)
|| codepoint == U'\u0085' // next line
|| codepoint == U'\u2028' // line separator
|| codepoint == U'\u2029' // paragraph separator
;
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_string_delimiter(char32_t codepoint) noexcept
{
return codepoint == U'"'
|| codepoint == U'\'';
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_ascii_letter(char32_t codepoint) noexcept
{
return (codepoint >= U'a' && codepoint <= U'z')
|| (codepoint >= U'A' && codepoint <= U'Z');
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_binary_digit(char32_t codepoint) noexcept
{
return codepoint == U'0' || codepoint == U'1';
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_octal_digit(char32_t codepoint) noexcept
{
return (codepoint >= U'0' && codepoint <= U'7');
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_decimal_digit(char32_t codepoint) noexcept
{
return (codepoint >= U'0' && codepoint <= U'9');
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_hex_digit(char32_t codepoint) noexcept
{
return (codepoint >= U'a' && codepoint <= U'f')
|| (codepoint >= U'A' && codepoint <= U'F')
|| is_decimal_digit(codepoint);
}
[[nodiscard]]
constexpr bool is_bare_key_start_character(char32_t codepoint) noexcept
{
return is_ascii_letter(codepoint)
|| is_decimal_digit(codepoint)
|| codepoint == U'-'
|| codepoint == U'_'
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/644 & toml/issues/687
|| codepoint == U'+'
|| is_unicode_letter(codepoint)
|| is_unicode_number(codepoint)
#endif
;
}
[[nodiscard]]
constexpr bool is_bare_key_character(char32_t codepoint) noexcept
{
return is_bare_key_start_character(codepoint)
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
|| is_unicode_combining_mark(codepoint)
#endif
;
}
[[nodiscard]]
constexpr bool is_value_terminator(char32_t codepoint) noexcept
{
return is_line_break(codepoint)
|| is_whitespace(codepoint)
|| codepoint == U']'
|| codepoint == U'}'
|| codepoint == U','
|| codepoint == U'#'
;
}
struct utf8_decoder final
{
// This decoder is based on code from here: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
//
// License:
//
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies
// or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
uint_least32_t state{};
char32_t codepoint{};
static constexpr uint8_t state_table[]
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
12,36,12,12,12,12,12,12,12,12,12,12
};
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool error() const noexcept
{
return state == uint_least32_t{ 12u };
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool has_code_point() const noexcept
{
return state == uint_least32_t{};
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool needs_more_input() const noexcept
{
return state > uint_least32_t{} && state != uint_least32_t{ 12u };
}
constexpr void operator () (uint8_t byte) noexcept
{
TOML_ASSERT(!error());
const auto type = state_table[byte];
codepoint = static_cast<char32_t>(
has_code_point()
? (uint_least32_t{ 255u } >> type) & byte
: (byte & uint_least32_t{ 63u }) | (static_cast<uint_least32_t>(codepoint) << 6)
);
state = state_table[state + uint_least32_t{ 256u } + type];
}
};
template <typename T>
class utf8_byte_stream;
template <typename CHAR>
class utf8_byte_stream<std::basic_string_view<CHAR>> final
{
static_assert(sizeof(CHAR) == 1_sz);
private:
std::basic_string_view<CHAR> source;
size_t position = {};
public:
explicit constexpr utf8_byte_stream(std::basic_string_view<CHAR> sv) noexcept
: source{ sv }
{
if (source.length() >= 3_sz
&& static_cast<uint8_t>(source[0]) == 0xEF_u8
&& static_cast<uint8_t>(source[1]) == 0xBB_u8
&& static_cast<uint8_t>(source[2]) == 0xBF_u8)
{
position += 3_sz;
}
}
[[nodiscard]]
constexpr bool eof() const noexcept
{
return position >= source.length();
}
[[nodiscard]]
constexpr bool error() const noexcept
{
return false;
}
[[nodiscard]]
constexpr std::optional<uint8_t> operator() () noexcept
{
if (position >= source.length())
return {};
return static_cast<uint8_t>(source[position++]);
}
};
template <typename CHAR>
class utf8_byte_stream<std::basic_istream<CHAR>> final
{
static_assert(sizeof(CHAR) == 1_sz);
private:
std::basic_istream<CHAR>* source;
public:
explicit utf8_byte_stream(std::basic_istream<CHAR>& stream) TOML_MAY_THROW
: source{ &stream }
{
if (*source)
{
static constexpr uint8_t bom[] {
0xEF_u8,
0xBB_u8,
0xBF_u8
};
using stream_traits = typename std::remove_pointer_t<decltype(source)>::traits_type;
const auto initial_pos = source->tellg();
size_t bom_pos{};
auto bom_char = source->get();
while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
{
bom_pos++;
bom_char = source->get();
}
if (!(*source) || bom_pos < 3_sz)
source->seekg(initial_pos);
}
}
[[nodiscard]]
bool eof() const noexcept
{
return source->eof();
}
[[nodiscard]]
bool error() const noexcept
{
return !(*source);
}
[[nodiscard]]
std::optional<uint8_t> operator() () TOML_MAY_THROW
{
auto val = source->get();
if (val == std::basic_istream<CHAR>::traits_type::eof())
return {};
return static_cast<uint8_t>(val);
}
};
struct utf8_codepoint final
{
char32_t value;
uint8_t bytes[4];
toml::source_position position;
template <typename CHAR = toml::string_char>
[[nodiscard]] TOML_ALWAYS_INLINE
std::basic_string_view<CHAR> as_view() const noexcept
{
static_assert(
sizeof(CHAR) == 1,
"The string view's underlying character type must be 1 byte in size."
);
return bytes[3]
? std::basic_string_view<CHAR>{ reinterpret_cast<const CHAR* const>(bytes), 4_sz }
: std::basic_string_view<CHAR>{ reinterpret_cast<const CHAR* const>(bytes) };
}
[[nodiscard]]
constexpr operator char32_t& () noexcept
{
return value;
}
[[nodiscard]]
constexpr operator const char32_t& () const noexcept
{
return value;
}
};
static_assert(std::is_trivial_v<utf8_codepoint>);
static_assert(std::is_standard_layout_v<utf8_codepoint>);
#if TOML_EXCEPTIONS
#define TOML_ERROR_CHECK (void)0
#define TOML_ERROR(...) throw toml::parse_error( __VA_ARGS__ )
#else
#define TOML_ERROR_CHECK if (err) return nullptr
#define TOML_ERROR(...) err.emplace( __VA_ARGS__ )
#endif
struct TOML_INTERFACE utf8_reader_interface
{
[[nodiscard]]
virtual const std::shared_ptr<const std::string>& source_path() const noexcept = 0;
[[nodiscard]]
virtual const utf8_codepoint* read_next() TOML_MAY_THROW = 0;
#if !TOML_EXCEPTIONS
[[nodiscard]]
virtual std::optional<toml::parse_error>&& error() noexcept = 0;
#endif
virtual ~utf8_reader_interface() noexcept = default;
};
template <typename T>
class TOML_EMPTY_BASES utf8_reader final
: public utf8_reader_interface
{
private:
utf8_byte_stream<T> stream;
utf8_decoder decoder;
utf8_codepoint prev{}, current{};
uint8_t current_byte_count{};
std::shared_ptr<const std::string> source_path_;
#if !TOML_EXCEPTIONS
std::optional<toml::parse_error> err;
#endif
public:
template <typename U, typename STR = std::string_view>
explicit utf8_reader(U && source, STR&& source_path = {})
TOML_CONDITIONAL_NOEXCEPT(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
: stream{ std::forward<U>(source) }
{
current.position = { 1u, 1u };
if (!source_path.empty())
source_path_ = std::make_shared<const std::string>(std::forward<STR>(source_path));
}
[[nodiscard]]
const std::shared_ptr<const std::string>& source_path() const noexcept override
{
return source_path_;
}
[[nodiscard]]
const utf8_codepoint* read_next() TOML_MAY_THROW override
{
TOML_ERROR_CHECK;
if (stream.eof())
return nullptr;
else if (stream.error())
TOML_ERROR("An error occurred while reading from the underlying stream", prev.position, source_path_ );
else if (decoder.error())
TOML_ERROR( "Encountered invalid utf-8 sequence", prev.position, source_path_ );
TOML_ERROR_CHECK;
while (true)
{
std::optional<uint8_t> nextByte;
if constexpr (!TOML_EXCEPTIONS || noexcept(stream()))
{
nextByte = stream();
}
#if TOML_EXCEPTIONS
else
{
try
{
nextByte = stream();
}
catch (const std::exception& exc)
{
throw toml::parse_error{ exc.what(), prev.position, source_path_ };
}
catch (...)
{
throw toml::parse_error{ "An unspecified error occurred", prev.position, source_path_ };
}
}
#endif
if (!nextByte)
{
if (stream.eof())
{
if (decoder.needs_more_input())
TOML_ERROR("Encountered EOF during incomplete utf-8 code point sequence", prev.position, source_path_);
return nullptr;
}
else
TOML_ERROR("An error occurred while reading from the underlying stream", prev.position, source_path_);
}
TOML_ERROR_CHECK;
decoder(*nextByte);
if (decoder.error())
TOML_ERROR( "Encountered invalid utf-8 sequence", prev.position, source_path_ );
TOML_ERROR_CHECK;
current.bytes[current_byte_count++] = *nextByte;
if (decoder.has_code_point())
{
current.value = decoder.codepoint;
prev = current;
std::memset(current.bytes, 0, sizeof(current.bytes));
current_byte_count = {};
if (is_line_break<false>(prev.value))
{
current.position.line++;
current.position.column = 1u;
}
else
current.position.column++;
return &prev;
}
}
}
#if !TOML_EXCEPTIONS
[[nodiscard]]
std::optional<toml::parse_error>&& error() noexcept override
{
return std::move(err);
}
#endif
};
template <typename CHAR>
utf8_reader(std::basic_string_view<CHAR>, std::string_view) -> utf8_reader<std::basic_string_view<CHAR>>;
template <typename CHAR>
utf8_reader(std::basic_istream<CHAR>&, std::string_view) -> utf8_reader<std::basic_istream<CHAR>>;
template <typename CHAR>
utf8_reader(std::basic_string_view<CHAR>, std::string&&) -> utf8_reader<std::basic_string_view<CHAR>>;
template <typename CHAR>
utf8_reader(std::basic_istream<CHAR>&, std::string&&) -> utf8_reader<std::basic_istream<CHAR>>;
#if !TOML_EXCEPTIONS
#undef TOML_ERROR_CHECK
#define TOML_ERROR_CHECK if (reader.error()) return nullptr
#endif
class TOML_EMPTY_BASES utf8_buffered_reader final
: public utf8_reader_interface
{
public:
static constexpr auto max_history_length = 64_sz;
private:
static constexpr auto history_buffer_size = max_history_length - 1_sz; //the 'head' is stored in the underlying reader
utf8_reader_interface& reader;
struct
{
utf8_codepoint buffer[history_buffer_size];
size_t count, first;
}
history = {};
const utf8_codepoint* head = {};
size_t negative_offset = {};
public:
explicit utf8_buffered_reader(utf8_reader_interface& reader_) noexcept
: reader{ reader_ }
{}
[[nodiscard]]
const std::shared_ptr<const std::string>& source_path() const noexcept override
{
return reader.source_path();
}
[[nodiscard]]
const utf8_codepoint* read_next() TOML_MAY_THROW override
{
TOML_ERROR_CHECK;
if (negative_offset)
{
negative_offset--;
// an entry negative offset of 1 just means "replay the current head"
if (!negative_offset)
return head;
// otherwise step back into the history buffer
else
return history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size);
}
else
{
// first character read from stream
if (!history.count && !head) TOML_UNLIKELY
head = reader.read_next();
// subsequent characters and not eof
else if (head)
{
if (history.count < history_buffer_size) TOML_UNLIKELY
history.buffer[history.count++] = *head;
else
history.buffer[(history.first++ + history_buffer_size) % history_buffer_size] = *head;
head = reader.read_next();
}
return head;
}
}
[[nodiscard]]
const utf8_codepoint* step_back(size_t count) noexcept
{
TOML_ERROR_CHECK;
TOML_ASSERT(history.count);
TOML_ASSERT(negative_offset + count <= history.count);
negative_offset += count;
return negative_offset
? history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size)
: head;
}
#if !TOML_EXCEPTIONS
[[nodiscard]]
std::optional<toml::parse_error>&& error() noexcept override
{
return reader.error();
}
#endif
};
#undef TOML_ERROR_CHECK
#undef TOML_ERROR
}

View File

@ -0,0 +1,985 @@
//# this file was generated by generate_unicode_functions.py
#pragma once
#include "toml_common.h"
#define TOML_ASSUME_CODEPOINT_BETWEEN(first, last) \
TOML_ASSUME(codepoint >= first); \
TOML_ASSUME(codepoint <= last)
namespace toml::impl
{
/// \brief Returns true if a codepoint belongs to any of these categories: Ll, Lm, Lo, Lt, Lu
[[nodiscard]]
constexpr bool is_unicode_letter(char32_t codepoint) noexcept
{
if (codepoint < U'\u00AA' || codepoint > U'\U0002FA1D')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u00AA', U'\U0002FA1D');
switch ((static_cast<uint_least32_t>(codepoint) - 0xAAu) / 3046u)
{
case 0:
{
if (codepoint > U'\u0C8F')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u00AA', U'\u0C8F');
switch ((static_cast<uint_least32_t>(codepoint) - 0xAAu) / 64u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAAull)) & 0xFFFFDFFFFFC10801ull;
case 1: return codepoint != U'\u00F7';
case 8: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x2AAull)) & 0x7C000FFF0FFFFFFull;
case 9: return codepoint != U'\u02EA';
case 10: return false;
case 11: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x370ull)) & 0x3FBFFFFD740BCDFull;
case 13: return codepoint != U'\u03F6';
case 15: return codepoint <= U'\u0481' || codepoint >= U'\u048A';
case 18: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x52Aull)) & 0xFFC09FFFFFFFFFBFull;
case 21: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x5EAull)) & 0xFFC00000000001E1ull;
case 23: return codepoint != U'\u066A';
case 24: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x6AAull)) & 0x18000BFFFFFFFFFFull;
case 25: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x6EEull)) & 0xFFFFFF400027003ull;
case 26: return codepoint <= U'\u072F' || codepoint >= U'\u074D';
case 28: return codepoint <= U'\u07B1' || codepoint >= U'\u07CA';
case 29: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x7EAull)) & 0x44010FFFFFC10C01ull;
case 30: return codepoint <= U'\u0858' || codepoint >= U'\u0860';
case 31: return codepoint <= U'\u086A' || codepoint >= U'\u08A0';
case 32: return codepoint != U'\u08B5';
case 34: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x92Aull)) & 0xFFC0400008FFFFull;
case 35: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x971ull)) & 0xFFFFFCCFF0FFFFull;
case 36: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x9AAull)) & 0xEC00100008F17Full;
case 37: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x9F0ull)) & 0x1FFFFF987E01003ull;
case 38: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA2Aull)) & 0x1780000000DB7Full;
case 39: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA72ull)) & 0x7FFFFEEFF80007ull;
case 40: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAAAull)) & 0xC000400008FB7Full;
case 41: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAF9ull)) & 0xFFFFFCCFF001ull;
case 42: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xB2Aull)) & 0xEC00000008FB7Full;
case 43: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xB71ull)) & 0x18C6B1EE3F40001ull;
case 44: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xBAAull)) & 0x400000FFF1ull;
case 45: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xC05ull)) & 0xFFFFFEEFFull;
case 46: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xC2Aull)) & 0xC1C0000008FFFFull;
case 47: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xC80u)) & 0xDFE1u;
default: return true;
}
// chunk summary: 1867 codepoints from 117 ranges (spanning a search area of 3046)
}
case 1:
{
if (codepoint < U'\u0C90' || codepoint > U'\u1875')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0C90', U'\u1875');
switch ((static_cast<uint_least32_t>(codepoint) - 0xC90u) / 64u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xC90ull)) & 0x23EFFDFFFFFDull;
case 1: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xCDEull)) & 0x37F800018000Dull;
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xD10ull)) & 0x400027FFFFFFFFFDull;
case 3: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xD54ull)) & 0xFFE0FC000003807ull;
case 4: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xD90ull)) & 0x7F2FFBFFFFFC7Full;
case 6: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xE10ull)) & 0x7F000DFFFFFFFFull;
case 7: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xE81u)) & 0x7BEBu;
case 8: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xE90ull)) & 0x5F200DFFAFFFFFull;
case 9: return codepoint <= U'\u0EDF' || codepoint >= U'\u0F00';
case 10: return codepoint != U'\u0F10';
case 11: return codepoint <= U'\u0F6C' || codepoint >= U'\u0F88';
case 12: return false;
case 14: return codepoint <= U'\u102A' || codepoint >= U'\u103F';
case 15: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1050ull)) & 0x4003FFE1C0623C3Full;
case 16: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10A0ull)) & 0x20BFFFFFFFFFull;
case 17: return codepoint != U'\u10FB';
case 22: return codepoint != U'\u1249';
case 23: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1250ull)) & 0x3DFFFFFFFFFF3D7Full;
case 24: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1290ull)) & 0xFF3D7F3DFFFFFFFFull;
case 25: return codepoint != U'\u12D7';
case 26: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1310ull)) & 0xFFFFFFFFFFFFFF3Dull;
case 27: return codepoint <= U'\u135A' || codepoint >= U'\u1380';
case 29: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x13D0ull)) & 0xFFFE3F3FFFFFFFFFull;
case 39: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1650ull)) & 0xFFFEFFFF9FFFFFFFull;
case 40: return codepoint <= U'\u169A' || codepoint >= U'\u16A0';
case 41: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x16D0ull)) & 0xDFFF01FE07FFFFFFull;
case 42: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1710ull)) & 0xFFFF0003FFFF0003ull;
case 43: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1750ull)) & 0xFFFF0001DFFF0003ull;
case 45: return codepoint <= U'\u17D7' || codepoint >= U'\u17DC';
default: return true;
}
// chunk summary: 2139 codepoints from 86 ranges (spanning a search area of 3046)
}
case 2:
{
if (codepoint < U'\u1876' || codepoint > U'\u2184')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u1876', U'\u2184');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1876u) / 63u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1876ull)) & 0x7C17FFFFFFFE7C07ull;
case 2: return codepoint <= U'\u18F5' || codepoint >= U'\u1900';
case 3: return codepoint <= U'\u196D' || codepoint >= U'\u1970';
case 4: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1972ull)) & 0x43FFFFFFFFFFC007ull;
case 6: return codepoint <= U'\u1A16' || codepoint >= U'\u1A20';
case 9: return false;
case 11: return codepoint <= U'\u1B33' || codepoint >= U'\u1B45';
case 13: return codepoint <= U'\u1BAF' || codepoint >= U'\u1BBA';
case 15: return codepoint <= U'\u1C4F' || codepoint >= U'\u1C5A';
case 16: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1C66ull)) & 0x7FFFFC07FCFFFFFFull;
case 17: return codepoint <= U'\u1CBA' || codepoint >= U'\u1CBD';
case 18: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1CE9ull)) & 0x3FFFFFFFF8237EFull;
case 26: return codepoint <= U'\u1F15' || codepoint >= U'\u1F18';
case 27: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1F1Bull)) & 0x5FE7E7FFFFFFFFE7ull;
case 28: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1F5Bull)) & 0x3FFFFFE7FFFFFFF5ull;
case 29: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1F99ull)) & 0x678FEE2FEFFFFFFFull;
case 30: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1FD8ull)) & 0x1FDC1FFF0Full;
case 31: return false;
case 32: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x2071ull)) & 0xF80004001ull;
case 34: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x2102u)) & 0x1FF21u;
case 35: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x2113ull)) & 0x87C1E7FF7AA07C5ull;
default: return true;
}
// chunk summary: 1328 codepoints from 65 ranges (spanning a search area of 2319)
}
case 3:
{
if (codepoint < U'\u2C00' || codepoint > U'\u3041')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u2C00', U'\u3041');
switch ((static_cast<uint_least32_t>(codepoint) - 0x2C00u) / 61u)
{
case 0: return codepoint != U'\u2C2F';
case 1: return codepoint != U'\u2C5F';
case 2: return true;
case 3: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x2CB7ull)) & 0x18F03FFFFFFFFFFFull;
case 4: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x2D00ull)) & 0x120BFFFFFFFFFull;
case 5: return true;
case 6: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x2D6Full)) & 0xEFE00FFFFFE0001ull;
case 7: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x2DABull)) & 0xFEFEFEFEFEFEFull;
case 9: return true;
case 16: return true;
case 17: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x3031u)) & 0x10C1Fu;
default: return false;
}
// chunk summary: 420 codepoints from 24 ranges (spanning a search area of 1090)
}
case 4:
{
if (codepoint < U'\u3042' || codepoint > U'\u3C27')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u3042', U'\u3C27');
switch ((static_cast<uint_least32_t>(codepoint) - 0x3042u) / 64u)
{
case 1: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x3082ull)) & 0xFFFFFFFFB81FFFFFull;
case 2: return codepoint != U'\u30FB';
case 3: return codepoint != U'\u3102';
case 5: return codepoint <= U'\u318E' || codepoint >= U'\u31A0';
case 7: return false;
case 8: return false;
case 9: return false;
case 10: return false;
case 11: return false;
case 12: return false;
case 13: return false;
default: return true;
}
// chunk summary: 2450 codepoints from 9 ranges (spanning a search area of 3046)
}
case 6: return codepoint <= U'\u4DB4' || codepoint >= U'\u4E00';
case 13:
{
if (codepoint < U'\u9B58' || codepoint > U'\uA73D')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u9B58', U'\uA73D');
switch ((static_cast<uint_least32_t>(codepoint) - 0x9B58u) / 64u)
{
case 18: return codepoint <= U'\u9FEE' || codepoint >= U'\uA000';
case 38: return codepoint <= U'\uA4FD' || codepoint >= U'\uA500';
case 42: return codepoint <= U'\uA60C' || codepoint >= U'\uA610';
case 43: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA618ull)) & 0xFFFFFF00000C00FFull;
case 44: return codepoint <= U'\uA66E' || codepoint >= U'\uA67F';
case 45: return codepoint <= U'\uA69D' || codepoint >= U'\uA6A0';
case 46: return codepoint <= U'\uA6E5' || codepoint >= U'\uA717';
case 47: return codepoint <= U'\uA71F' || codepoint >= U'\uA722';
default: return true;
}
// chunk summary: 2858 codepoints from 11 ranges (spanning a search area of 3046)
}
case 14:
{
if (codepoint < U'\uA73E' || codepoint > U'\uB323')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\uA73E', U'\uB323');
switch ((static_cast<uint_least32_t>(codepoint) - 0xA73Eu) / 64u)
{
case 1: return codepoint <= U'\uA788' || codepoint >= U'\uA78B';
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA7BEull)) & 0xFE000000000001F3ull;
case 3: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA7FEull)) & 0x1FFFFFDEEFull;
case 6: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xA8F2u)) & 0xA3Fu;
case 7: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA8FEull)) & 0xFFFC00FFFFFFF001ull;
case 8: return codepoint <= U'\uA946' || codepoint >= U'\uA960';
case 10: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA9CFull)) & 0x7801FFBE0001ull;
case 11: return codepoint != U'\uA9FF';
case 12: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAA40ull)) & 0x47FFFFF00000FF7ull;
case 13: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAA7Eull)) & 0xF98BFFFFFFFFFFFFull;
case 14: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAAC0ull)) & 0x1C07FF38000005ull;
case 15: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAB01ull)) & 0x1FFFBFBF803F3F3Full;
case 16: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAB3Eull)) & 0xFFFC03FFDFFFFFFFull;
default: return true;
}
// chunk summary: 2616 codepoints from 43 ranges (spanning a search area of 3046)
}
case 18: return codepoint <= U'\uD7A2' || (codepoint >= U'\uD7B0' && codepoint <= U'\uD7C6')
|| codepoint >= U'\uD7CB';
case 19: return false;
case 20: return codepoint <= U'\uFA6D' || codepoint >= U'\uFA70';
case 21:
{
if (codepoint < U'\uFA88' || codepoint > U'\U0001066D')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\uFA88', U'\U0001066D');
switch ((static_cast<uint_least32_t>(codepoint) - 0xFA88u) / 64u)
{
case 1: return codepoint <= U'\uFAD9' || codepoint >= U'\uFB00';
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xFB13ull)) & 0x1B6BEFFFBFF41Full;
case 12: return codepoint <= U'\uFD8F' || codepoint >= U'\uFD92';
case 14: return false;
case 15: return codepoint != U'\uFE48';
case 18: return codepoint <= U'\uFF3A' || codepoint >= U'\uFF41';
case 19: return codepoint <= U'\uFF5A' || codepoint >= U'\uFF66';
case 20: return codepoint <= U'\uFFBE' || codepoint >= U'\uFFC2';
case 21: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xFFCAull)) & 0x3FC0000000073F3Full;
case 22: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10008ull)) & 0xFFB7FFFF7FFFFFEFull;
case 23: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10048ull)) & 0xFF000000003FFF3Full;
case 26: return false;
case 27: return false;
case 28: return false;
case 29: return false;
case 30: return false;
case 32: return codepoint <= U'\U0001029C' || codepoint >= U'\U000102A0';
case 33: return codepoint <= U'\U000102D0' || codepoint >= U'\U00010300';
case 34: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10308ull)) & 0xFDFFFFE000FFFFFFull;
case 35: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10348ull)) & 0xFF003FFFFFFFFF03ull;
case 36: return codepoint <= U'\U0001039D' || codepoint >= U'\U000103A0';
case 37: return codepoint <= U'\U000103CF' || codepoint >= U'\U00010400';
case 40: return codepoint <= U'\U0001049D' || codepoint >= U'\U000104B0';
case 41: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x104C8ull)) & 0xFF0FFFFFFFFF0FFFull;
case 42: return codepoint <= U'\U00010527' || codepoint >= U'\U00010530';
case 44: return false;
default: return true;
}
// chunk summary: 1924 codepoints from 46 ranges (spanning a search area of 3046)
}
case 22:
{
if (codepoint < U'\U0001066E' || codepoint > U'\U0001122B')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U0001066E', U'\U0001122B');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1066Eu) / 64u)
{
case 3: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1072Eull)) & 0x3FC00FFFFFC01FFull;
case 4: return false;
case 5: return false;
case 6: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10800ull)) & 0x3FFFFFFFFD3Full;
case 7: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1082Eull)) & 0xFFFC00FFFFFE46FFull;
case 8: return codepoint <= U'\U00010876' || codepoint >= U'\U00010880';
case 10: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x108EEull)) & 0xFFFC00FFFFFC00DFull;
case 13: return codepoint <= U'\U000109B7' || codepoint >= U'\U000109BE';
case 14: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10A00ull)) & 0x3FFFFEEF0001ull;
case 15: return codepoint <= U'\U00010A35' || codepoint >= U'\U00010A60';
case 16: return codepoint <= U'\U00010A7C' || codepoint >= U'\U00010A80';
case 17: return codepoint != U'\U00010AAE';
case 19: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x10B2Eull)) & 0xFFFC00FFFFFC00FFull;
case 20: return codepoint <= U'\U00010B72' || codepoint >= U'\U00010B80';
case 21: return false;
case 25: return codepoint <= U'\U00010CB2' || codepoint >= U'\U00010CC0';
case 26: return codepoint <= U'\U00010CF2' || codepoint >= U'\U00010D00';
case 27: return false;
case 28: return false;
case 29: return false;
case 30: return false;
case 31: return false;
case 32: return false;
case 33: return false;
case 34: return codepoint <= U'\U00010F1C' || codepoint >= U'\U00010F27';
case 36: return false;
case 38: return codepoint <= U'\U00010FF6' || codepoint >= U'\U00011003';
case 41: return codepoint <= U'\U000110AF' || codepoint >= U'\U000110D0';
case 43: return codepoint <= U'\U00011144' || codepoint >= U'\U00011150';
case 44: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1116Eull)) & 0xFFFFFFFFFFE0011Full;
case 45: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x111AEull)) & 0x50000078001Full;
case 46: return codepoint != U'\U000111EE';
default: return true;
}
// chunk summary: 1312 codepoints from 50 ranges (spanning a search area of 3006)
}
case 23:
{
if (codepoint < U'\U00011280' || codepoint > U'\U00011D98')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U00011280', U'\U00011D98');
switch ((static_cast<uint_least32_t>(codepoint) - 0x11280u) / 64u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x11280ull)) & 0xFFFF01FFBFFFBD7Full;
case 1: return true;
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x11305ull)) & 0x11F6FEFFFFFCCFFull;
case 3: return codepoint <= U'\U00011350' || codepoint >= U'\U0001135D';
case 6: return true;
case 7: return codepoint <= U'\U0001144A' || codepoint >= U'\U0001145F';
case 8: return true;
case 9: return codepoint != U'\U000114C0';
case 12: return true;
case 13: return true;
case 14: return true;
case 15: return true;
case 16: return codepoint <= U'\U000116AA' || codepoint >= U'\U000116B8';
case 18: return true;
case 22: return true;
case 24: return true;
case 25: return codepoint <= U'\U000118DF' || codepoint >= U'\U000118FF';
case 28: return codepoint <= U'\U000119A7' || codepoint >= U'\U000119AA';
case 29: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x119C0ull)) & 0xA0001FFFFull;
case 30: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x11A00ull)) & 0x407FFFFFFFFF801ull;
case 31: return codepoint <= U'\U00011A50' || codepoint >= U'\U00011A5C';
case 32: return codepoint <= U'\U00011A89' || codepoint >= U'\U00011A9D';
case 33: return true;
case 38: return codepoint != U'\U00011C09';
case 39: return codepoint <= U'\U00011C40' || codepoint >= U'\U00011C72';
case 40: return true;
case 42: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x11D00ull)) & 0x1FFFFFFFFFB7Full;
case 43: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x11D46ull)) & 0x3FFFFF6FC000001ull;
case 44: return codepoint <= U'\U00011D89' || codepoint >= U'\U00011D98';
default: return false;
}
// chunk summary: 888 codepoints from 54 ranges (spanning a search area of 2841)
}
case 24: return codepoint <= U'\U00011EF2' || (codepoint >= U'\U00012000' && codepoint <= U'\U00012399')
|| codepoint >= U'\U00012480';
case 26: return false;
case 28: return false;
case 29: return false;
case 30:
{
if (codepoint < U'\U00016800' || codepoint > U'\U00017183')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U00016800', U'\U00017183');
switch ((static_cast<uint_least32_t>(codepoint) - 0x16800u) / 63u)
{
case 9: return codepoint <= U'\U00016A38' || codepoint >= U'\U00016A40';
case 10: return false;
case 13: return codepoint <= U'\U00016B43' || codepoint >= U'\U00016B63';
case 14: return codepoint <= U'\U00016B77' || codepoint >= U'\U00016B7D';
case 15: return false;
case 16: return false;
case 17: return false;
case 18: return false;
case 19: return false;
case 20: return false;
case 21: return false;
case 22: return false;
case 23: return false;
case 24: return false;
case 27: return false;
case 29: return codepoint <= U'\U00016F4A' || codepoint >= U'\U00016F50';
case 31: return false;
case 32: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x16FE0ull)) & 0x7FFFFFFF0000000Bull;
default: return true;
}
// chunk summary: 1266 codepoints from 14 ranges (spanning a search area of 2436)
}
case 32: return codepoint <= U'\U000187F6' || codepoint >= U'\U00018800';
case 34: return false;
case 35: return false;
case 36: return codepoint <= U'\U0001B11E' || (codepoint >= U'\U0001B150' && codepoint <= U'\U0001B152')
|| (codepoint >= U'\U0001B164' && codepoint <= U'\U0001B167') || codepoint >= U'\U0001B170';
case 37: return codepoint <= U'\U0001BC6A' || (codepoint >= U'\U0001BC70' && codepoint <= U'\U0001BC7C')
|| (codepoint >= U'\U0001BC80' && codepoint <= U'\U0001BC88') || codepoint >= U'\U0001BC90';
case 38: return false;
case 39:
{
if (codepoint < U'\U0001D400' || codepoint > U'\U0001D7CB')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U0001D400', U'\U0001D7CB');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1D400u) / 61u)
{
case 1: return codepoint != U'\U0001D455';
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D47Aull)) & 0x1FF79937FFFFFFFFull;
case 3: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D4B7ull)) & 0x1FFFFFFFFFFFDFD7ull;
case 4: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D4F4ull)) & 0x1FFFFDFDFE7BFFFFull;
case 5: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D531ull)) & 0x1FFFFFFEFE2FBDFFull;
case 11: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D69Full)) & 0xFFFFFFBFFFFFE7Full;
case 12: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D6DCull)) & 0x1DFFFFFF7FFFFFFFull;
case 13: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D719ull)) & 0x1FBFFFFFEFFFFFFFull;
case 14: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D756ull)) & 0x1FF7FFFFFDFFFFFFull;
case 15: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D793ull)) & 0x1FEFFFFFFBFFFFFull;
default: return true;
}
// chunk summary: 936 codepoints from 30 ranges (spanning a search area of 972)
}
case 40:
{
if (codepoint < U'\U0001E100' || codepoint > U'\U0001E87F')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U0001E100', U'\U0001E87F');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1E100u) / 64u)
{
case 0: return codepoint <= U'\U0001E12C' || codepoint >= U'\U0001E137';
case 1: return true;
case 7: return true;
case 28: return true;
case 29: return true;
default: return false;
}
// chunk summary: 225 codepoints from 5 ranges (spanning a search area of 1920)
}
case 41:
{
if (codepoint < U'\U0001E880' || codepoint > U'\U0001EEBB')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U0001E880', U'\U0001EEBB');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1E880u) / 64u)
{
case 0: return true;
case 1: return true;
case 2: return true;
case 3: return codepoint <= U'\U0001E943' || codepoint >= U'\U0001E94B';
case 22: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1EE00ull)) & 0xAF7FE96FFFFFFEFull;
case 23: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1EE42ull)) & 0x17BDFDE5AAA5BAA1ull;
case 24: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1EE80ull)) & 0xFFFFBEE0FFFFBFFull;
default: return false;
}
// chunk summary: 279 codepoints from 36 ranges (spanning a search area of 1596)
}
case 58: return codepoint <= U'\U0002B733' || (codepoint >= U'\U0002B740' && codepoint <= U'\U0002B81C')
|| codepoint >= U'\U0002B820';
case 60: return codepoint <= U'\U0002CEA0' || codepoint >= U'\U0002CEB0';
default: return true;
}
// chunk summary: 125582 codepoints from 607 ranges (spanning a search area of 194932)
}
/// \brief Returns true if a codepoint belongs to any of these categories: Nd, Nl
[[nodiscard]]
constexpr bool is_unicode_number(char32_t codepoint) noexcept
{
if (codepoint < U'\u0660' || codepoint > U'\U0001E959')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0660', U'\U0001E959');
switch ((static_cast<uint_least32_t>(codepoint) - 0x660u) / 1932u)
{
case 0:
{
if (codepoint > U'\u0DEB')
return false;
return ((static_cast<uint_least32_t>(codepoint) - 0x660u) / 63u) & 0x55555025ull;
// chunk summary: 126 codepoints from 13 ranges (spanning a search area of 1932)
}
case 1:
{
if (codepoint < U'\u0DEC' || codepoint > U'\u1099')
return false;
return ((static_cast<uint_least32_t>(codepoint) - 0xDECu) / 63u) & 0x63Bull;
// chunk summary: 54 codepoints from 6 ranges (spanning a search area of 686)
}
case 2:
{
if (codepoint < U'\u16EE' || codepoint > U'\u1C59')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u16EE', U'\u1C59');
switch ((static_cast<uint_least32_t>(codepoint) - 0x16EEu) / 64u)
{
case 0: return true;
case 3: return true;
case 4: return true;
case 9: return true;
case 11: return true;
case 14: return codepoint <= U'\u1A89' || codepoint >= U'\u1A90';
case 17: return true;
case 19: return true;
case 21: return codepoint <= U'\u1C49' || codepoint >= U'\u1C50';
default: return false;
}
// chunk summary: 103 codepoints from 11 ranges (spanning a search area of 1388)
}
case 3: return codepoint <= U'\u2182' || codepoint >= U'\u2185';
case 5: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x3007ull)) & 0xE0007FC000001ull;
case 21:
{
if (codepoint < U'\uA620' || codepoint > U'\uABF9')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\uA620', U'\uABF9');
switch ((static_cast<uint_least32_t>(codepoint) - 0xA620u) / 63u)
{
case 0: return true;
case 3: return true;
case 10: return true;
case 11: return codepoint <= U'\uA8D9' || codepoint >= U'\uA900';
case 14: return true;
case 15: return codepoint <= U'\uA9D9' || codepoint >= U'\uA9F0';
case 17: return true;
case 23: return true;
default: return false;
}
// chunk summary: 80 codepoints from 8 ranges (spanning a search area of 1498)
}
case 32: return true;
case 33:
{
if (codepoint < U'\U00010140' || codepoint > U'\U000104A9')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U00010140', U'\U000104A9');
switch ((static_cast<uint_least32_t>(codepoint) - 0x10140u) / 63u)
{
case 0: return true;
case 8: return codepoint <= U'\U00010341' || codepoint >= U'\U0001034A';
case 10: return true;
case 13: return true;
default: return false;
}
// chunk summary: 70 codepoints from 5 ranges (spanning a search area of 874)
}
case 34: return true;
case 35:
{
if (codepoint < U'\U00011066' || codepoint > U'\U000114D9')
return false;
return ((static_cast<uint_least32_t>(codepoint) - 0x11066u) / 64u) & 0x2842Dull;
// chunk summary: 70 codepoints from 7 ranges (spanning a search area of 1140)
}
case 36:
{
if (codepoint < U'\U00011650' || codepoint > U'\U00011D59')
return false;
return ((static_cast<uint_least32_t>(codepoint) - 0x11650u) / 63u) & 0x1100040Bull;
// chunk summary: 60 codepoints from 6 ranges (spanning a search area of 1802)
}
case 37: return codepoint <= U'\U00011DA9' || codepoint >= U'\U00012400';
case 47: return codepoint <= U'\U00016A69' || codepoint >= U'\U00016B50';
case 61: return true;
case 62: return true;
case 63: return codepoint <= U'\U0001E2F9' || codepoint >= U'\U0001E950';
default: return false;
}
// chunk summary: 856 codepoints from 70 ranges (spanning a search area of 123642)
}
/// \brief Returns true if a codepoint belongs to any of these categories: Mn, Mc
[[nodiscard]]
constexpr bool is_unicode_combining_mark(char32_t codepoint) noexcept
{
if (codepoint < U'\u0300' || codepoint > U'\U000E01EF')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0300', U'\U000E01EF');
switch ((static_cast<uint_least32_t>(codepoint) - 0x300u) / 14332u)
{
case 0:
{
if (codepoint > U'\u309A')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0300', U'\u309A');
switch ((static_cast<uint_least32_t>(codepoint) - 0x300u) / 183u)
{
case 0: return true;
case 2: return true;
case 3: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x591ull)) & 0x5B5FFFFFFFFFFFull;
case 4: return codepoint <= U'\u061A' || (codepoint >= U'\u064B' && codepoint <= U'\u065F')
|| codepoint == U'\u0670';
case 5:
{
if (codepoint < U'\u06D6' || codepoint > U'\u0749')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u06D6', U'\u0749');
switch ((static_cast<uint_least32_t>(codepoint) - 0x6D6u) / 58u)
{
case 0: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x6D6u)) & 0xF67E7Fu;
case 1: return codepoint <= U'\u0711' || codepoint >= U'\u0730';
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 46 codepoints from 6 ranges (spanning a search area of 116)
}
case 6: return codepoint == U'\u074A' || (codepoint >= U'\u07A6' && codepoint <= U'\u07B0')
|| (codepoint >= U'\u07EB' && codepoint <= U'\u07F3') || codepoint == U'\u07FD';
case 7:
{
if (codepoint < U'\u0816' || codepoint > U'\u085B')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0816', U'\u085B');
switch ((static_cast<uint_least32_t>(codepoint) - 0x816u) / 35u)
{
case 0: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x816u)) & 0xFBBFEFu;
default: return true;
}
// chunk summary: 24 codepoints from 5 ranges (spanning a search area of 70)
}
case 8:
{
if (codepoint < U'\u08D3' || codepoint > U'\u0963')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u08D3', U'\u0963');
switch ((static_cast<uint_least32_t>(codepoint) - 0x8D3u) / 49u)
{
case 0: return codepoint != U'\u08E2';
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x93Aull)) & 0x3003FBFFFF7ull;
default: return false;
}
// chunk summary: 78 codepoints from 6 ranges (spanning a search area of 145)
}
case 9:
{
if (codepoint < U'\u0981' || codepoint > U'\u0A03')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0981', U'\u0A03');
switch ((static_cast<uint_least32_t>(codepoint) - 0x981u) / 44u)
{
case 1: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x9BCu)) & 0x80399FDu;
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x9E2ull)) & 0x390000003ull;
default: return true;
}
// chunk summary: 23 codepoints from 9 ranges (spanning a search area of 131)
}
case 10:
{
if (codepoint < U'\u0A3C' || codepoint > U'\u0ACD')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0A3C', U'\u0ACD');
switch ((static_cast<uint_least32_t>(codepoint) - 0xA3Cu) / 49u)
{
case 0: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xA3Cu)) & 0x23987Du;
case 1: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xA70u)) & 0xE0023u;
case 2: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xABCu)) & 0x3BBFDu;
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 33 codepoints from 12 ranges (spanning a search area of 146)
}
case 11:
{
if (codepoint < U'\u0AE2' || codepoint > U'\u0B82')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0AE2', U'\u0B82');
switch ((static_cast<uint_least32_t>(codepoint) - 0xAE2u) / 54u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAE2ull)) & 0x3BF000003ull;
case 1: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xB3Cu)) & 0x399FDu;
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xB56ull)) & 0x100000003003ull;
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 29 codepoints from 10 ranges (spanning a search area of 161)
}
case 12:
{
if (codepoint < U'\u0BBE' || codepoint > U'\u0C4A')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0BBE', U'\u0C4A');
switch ((static_cast<uint_least32_t>(codepoint) - 0xBBEu) / 47u)
{
case 0: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xBBEu)) & 0x200F71Fu;
case 2: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xC3Eu)) & 0x177Fu;
default: return true;
}
// chunk summary: 29 codepoints from 8 ranges (spanning a search area of 141)
}
case 13:
{
if (codepoint < U'\u0C4B' || codepoint > U'\u0D01')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0C4B', U'\u0D01');
switch ((static_cast<uint_least32_t>(codepoint) - 0xC4Bu) / 61u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xC4Bull)) & 0x1C0000001800C07ull;
case 1: return codepoint != U'\u0C88';
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xCC6ull)) & 0xC000000300180F7ull;
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 31 codepoints from 11 ranges (spanning a search area of 183)
}
case 14:
{
if (codepoint < U'\u0D02' || codepoint > U'\u0D83')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0D02', U'\u0D83');
switch ((static_cast<uint_least32_t>(codepoint) - 0xD02u) / 44u)
{
case 1: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xD3Bu)) & 0x1007BBFBu;
case 2: return codepoint <= U'\u0D63' || codepoint >= U'\u0D82';
default: return true;
}
// chunk summary: 23 codepoints from 8 ranges (spanning a search area of 130)
}
case 15:
{
if (codepoint < U'\u0DCA' || codepoint > U'\u0E4E')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0DCA', U'\u0E4E');
switch ((static_cast<uint_least32_t>(codepoint) - 0xDCAu) / 45u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xDCAull)) & 0x300003FD7E1ull;
case 2: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xE31u)) & 0x3FC003F9u;
default: return false;
}
// chunk summary: 34 codepoints from 8 ranges (spanning a search area of 133)
}
case 16: return codepoint == U'\u0EB1' || (codepoint >= U'\u0EB4' && codepoint <= U'\u0EBC')
|| (codepoint >= U'\u0EC8' && codepoint <= U'\u0ECD') || codepoint >= U'\u0F18';
case 17:
{
if (codepoint < U'\u0F35' || codepoint > U'\u0FC6')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u0F35', U'\u0FC6');
switch ((static_cast<uint_least32_t>(codepoint) - 0xF35u) / 49u)
{
case 0: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xF35u)) & 0x615u;
case 1: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xF71ull)) & 0x3FF06FFFFFull;
case 2: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xF97ull)) & 0x803FFFFFFFFDull;
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 75 codepoints from 9 ranges (spanning a search area of 146)
}
case 18:
{
if (codepoint < U'\u102B' || codepoint > U'\u108F')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u102B', U'\u108F');
switch ((static_cast<uint_least32_t>(codepoint) - 0x102Bu) / 51u)
{
case 0: return codepoint <= U'\u103E' || codepoint >= U'\u1056';
case 1: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x105Eull)) & 0x2FFF00078FE77ull;
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 54 codepoints from 8 ranges (spanning a search area of 101)
}
case 19: return true;
case 22: return true;
case 28:
{
if (codepoint < U'\u1712' || codepoint > U'\u17BA')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\u1712', U'\u17BA');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1712u) / 57u)
{
case 0: return codepoint <= U'\u1714' || codepoint >= U'\u1732';
case 1: return codepoint <= U'\u1753' || codepoint >= U'\u1772';
default: return true;
}
// chunk summary: 17 codepoints from 5 ranges (spanning a search area of 169)
}
case 29: return codepoint <= U'\u17D3' || codepoint == U'\u17DD' || codepoint >= U'\u180B';
case 30: return codepoint <= U'\u1886' || codepoint == U'\u18A9' || codepoint >= U'\u1920';
case 31: return codepoint <= U'\u192B' || codepoint >= U'\u1930';
case 32: return codepoint <= U'\u1A1B' || (codepoint >= U'\u1A55' && codepoint <= U'\u1A5E')
|| (codepoint >= U'\u1A60' && codepoint <= U'\u1A7C') || codepoint == U'\u1A7F';
case 33: return codepoint <= U'\u1ABD' || (codepoint >= U'\u1B00' && codepoint <= U'\u1B04')
|| codepoint >= U'\u1B34';
case 34: return codepoint <= U'\u1B73' || (codepoint >= U'\u1B80' && codepoint <= U'\u1B82')
|| (codepoint >= U'\u1BA1' && codepoint <= U'\u1BAD') || codepoint >= U'\u1BE6';
case 35: return true;
case 36: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1CD0ull)) & 0x39021FFFFF7ull;
case 37: return codepoint != U'\u1D73';
case 41: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x20D0ull)) & 0x1FFE21FFFull;
case 58: return true;
case 59: return codepoint <= U'\u2D7F' || codepoint >= U'\u2DE0';
case 60: return true;
case 63: return codepoint <= U'\u302F' || codepoint >= U'\u3099';
default: return false;
}
// chunk summary: 1102 codepoints from 155 ranges (spanning a search area of 11675)
}
case 2:
{
if (codepoint < U'\uA66F' || codepoint > U'\uAAEF')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\uA66F', U'\uAAEF');
switch ((static_cast<uint_least32_t>(codepoint) - 0xA66Fu) / 61u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xA66Full)) & 0x1800000007FE1ull;
case 1: return false;
case 3: return false;
case 4: return false;
case 5: return false;
case 6: return (1u << (static_cast<uint_least32_t>(codepoint) - 0xA802u)) & 0x211u;
case 10: return codepoint <= U'\uA8F1' || codepoint >= U'\uA8FF';
case 11: return codepoint <= U'\uA92D' || codepoint >= U'\uA947';
case 12: return codepoint <= U'\uA953' || codepoint >= U'\uA980';
case 16: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAA43ull)) & 0x100000000000601ull;
case 17: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAA7Cull)) & 0x19D0000000000003ull;
case 18: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0xAABEull)) & 0x3E0000000000Bull;
default: return true;
}
// chunk summary: 136 codepoints from 27 ranges (spanning a search area of 1153)
}
case 3: return codepoint <= U'\uAAF6' || (codepoint >= U'\uABE3' && codepoint <= U'\uABEA')
|| codepoint >= U'\uABEC';
case 4:
{
if (codepoint < U'\uFB1E' || codepoint > U'\U00011A99')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\uFB1E', U'\U00011A99');
switch ((static_cast<uint_least32_t>(codepoint) - 0xFB1Eu) / 128u)
{
case 0: return true;
case 5: return true;
case 6: return true;
case 13: return true;
case 15: return true;
case 16: return true;
case 29: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x10A01u)) & 0x7837u;
case 30: return codepoint <= U'\U00010A3A' || codepoint >= U'\U00010A3F';
case 31: return true;
case 36: return true;
case 40: return true;
case 41: return true;
case 42: return codepoint <= U'\U00011046' || codepoint >= U'\U0001107F';
case 43: return codepoint <= U'\U000110BA' || codepoint >= U'\U00011100';
case 44: return codepoint <= U'\U00011134' || (codepoint >= U'\U00011145' && codepoint <= U'\U00011146')
|| codepoint == U'\U00011173' || codepoint >= U'\U00011180';
case 45: return codepoint <= U'\U000111C0' || codepoint >= U'\U000111C9';
case 46: return codepoint <= U'\U00011237' || codepoint >= U'\U0001123E';
case 47: return codepoint <= U'\U000112EA' || codepoint >= U'\U00011300';
case 48: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1133Bull)) & 0x3E3F980100733FBull;
case 50: return codepoint <= U'\U00011446' || codepoint >= U'\U0001145E';
case 51: return true;
case 53: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x115AFull)) & 0x60000003FE7Full;
case 54: return true;
case 55: return codepoint <= U'\U000116B7' || codepoint >= U'\U0001171D';
case 56: return true;
case 58: return true;
case 61: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x119D1ull)) & 0x3FF00000008FE7Full;
case 62:
{
if (codepoint < U'\U00011A33')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U00011A33', U'\U00011A99');
switch ((static_cast<uint_least32_t>(codepoint) - 0x11A33u) / 52u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x11A33ull)) & 0x1FFC0100F7Full;
default: return true;
}
// chunk summary: 39 codepoints from 5 ranges (spanning a search area of 103)
}
default: return false;
}
// chunk summary: 383 codepoints from 56 ranges (spanning a search area of 8060)
}
case 5:
{
if (codepoint < U'\U00011C2F' || codepoint > U'\U00011EF6')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U00011C2F', U'\U00011EF6');
switch ((static_cast<uint_least32_t>(codepoint) - 0x11C2Fu) / 60u)
{
case 0: return codepoint != U'\U00011C37';
case 1: return true;
case 2: return codepoint != U'\U00011CA8';
case 4: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x11D31u)) & 0x5FDA3Fu;
case 5: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x11D8Au)) & 0x1EDFu;
case 6: return true;
case 11: return true;
default: return false;
}
// chunk summary: 85 codepoints from 13 ranges (spanning a search area of 712)
}
case 6:
{
if (codepoint < U'\U00016AF0' || codepoint > U'\U00016F92')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U00016AF0', U'\U00016F92');
switch ((static_cast<uint_least32_t>(codepoint) - 0x16AF0u) / 63u)
{
case 0: return true;
case 1: return true;
case 17: return codepoint != U'\U00016F1F';
case 18: return codepoint <= U'\U00016F87' || codepoint >= U'\U00016F8F';
default: return false;
}
// chunk summary: 72 codepoints from 5 ranges (spanning a search area of 1187)
}
case 7: return true;
case 8:
{
if (codepoint < U'\U0001D165' || codepoint > U'\U0001E94A')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U0001D165', U'\U0001E94A');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1D165u) / 128u)
{
case 0:
{
if (codepoint > U'\U0001D1AD')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U0001D165', U'\U0001D1AD');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1D165u) / 37u)
{
case 0: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1D165ull)) & 0x1F3FC03F1Full;
case 1: return codepoint <= U'\U0001D18B' || codepoint >= U'\U0001D1AA';
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 30 codepoints from 5 ranges (spanning a search area of 73)
}
case 1: return true;
case 17: return codepoint <= U'\U0001DA36' || codepoint >= U'\U0001DA3B';
case 18:
{
if (codepoint < U'\U0001DA65' || codepoint > U'\U0001DAAF')
return false;
TOML_ASSUME_CODEPOINT_BETWEEN(U'\U0001DA65', U'\U0001DAAF');
switch ((static_cast<uint_least32_t>(codepoint) - 0x1DA65u) / 38u)
{
case 0: return (1u << (static_cast<uint_least32_t>(codepoint) - 0x1DA65u)) & 0x800100FFu;
case 1: return codepoint != U'\U0001DA8B';
TOML_NO_DEFAULT_CASE;
}
// chunk summary: 30 codepoints from 5 ranges (spanning a search area of 75)
}
case 29: return (1ull << (static_cast<uint_least64_t>(codepoint) - 0x1E000ull)) & 0x7DBF9FFFF7Full;
case 31: return true;
case 35: return true;
case 46: return true;
case 47: return true;
default: return false;
}
// chunk summary: 223 codepoints from 21 ranges (spanning a search area of 6118)
}
case 63: return true;
default: return false;
}
// chunk summary: 2255 codepoints from 282 ranges (spanning a search area of 917232)
}
}
#undef TOML_ASSUME_CODEPOINT_BETWEEN

113
include/toml++/toml_value.h Normal file
View File

@ -0,0 +1,113 @@
#pragma once
#include "toml_node.h"
namespace toml
{
template <typename T>
class value final
: public node
{
static_assert(
impl::is_value<T>,
"Template type parameter must be one of the basic value types"
);
private:
friend class impl::parser;
template <typename U>
[[nodiscard]] TOML_ALWAYS_INLINE
toml::value<U>* as_value() noexcept
{
if constexpr (std::is_same_v<T, U>)
return this;
else
return nullptr;
}
template <typename U>
[[nodiscard]] TOML_ALWAYS_INLINE
const toml::value<U>* as_value() const noexcept
{
if constexpr (std::is_same_v<T, U>)
return this;
else
return nullptr;
}
T val_;
public:
template <typename... U>
TOML_NODISCARD_CTOR
explicit value(U&&... args) TOML_CONDITIONAL_NOEXCEPT(std::is_nothrow_constructible_v<T, U &&...>)
: val_{ std::forward<U>(args)... }
{}
TOML_NODISCARD_CTOR
value(value&& other) noexcept
: node{ std::move(other) },
val_{ std::move(other.val_) }
{}
value& operator= (value&& rhs) noexcept
{
node::operator=(std::move(rhs));
val_ = std::move(rhs.val_);
return *this;
}
[[nodiscard]] bool is_string() const noexcept override { return std::is_same_v<T, string>; }
[[nodiscard]] bool is_integer() const noexcept override { return std::is_same_v<T, int64_t>; }
[[nodiscard]] bool is_floating_point() const noexcept override { return std::is_same_v<T, double>; }
[[nodiscard]] bool is_boolean() const noexcept override { return std::is_same_v<T, bool>; }
[[nodiscard]] bool is_date() const noexcept override { return std::is_same_v<T, date>; }
[[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<T, time>; }
[[nodiscard]] bool is_date_time() const noexcept override { return std::is_same_v<T, date_time>; }
[[nodiscard]] value<string>* as_string() noexcept override { return as_value<string>(); }
[[nodiscard]] value<int64_t>* as_integer() noexcept override { return as_value<int64_t>(); }
[[nodiscard]] value<double>* as_floating_point() noexcept override { return as_value<double>(); }
[[nodiscard]] value<bool>* as_boolean() noexcept override { return as_value<bool>(); }
[[nodiscard]] value<date>* as_date() noexcept override { return as_value<date>(); }
[[nodiscard]] value<time>* as_time() noexcept override { return as_value<time>(); }
[[nodiscard]] value<date_time>* as_date_time() noexcept override { return as_value<date_time>(); }
[[nodiscard]] const value<string>* as_string() const noexcept override { return as_value<string>(); }
[[nodiscard]] const value<int64_t>* as_integer() const noexcept override { return as_value<int64_t>(); }
[[nodiscard]] const value<double>* as_floating_point() const noexcept override { return as_value<double>(); }
[[nodiscard]] const value<bool>* as_boolean() const noexcept override { return as_value<bool>(); }
[[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(); }
[[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(); }
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(); }
[[nodiscard]] node_type type() const noexcept override
{
if constexpr (std::is_same_v<T, string>) return node_type::string;
else if constexpr (std::is_same_v<T, int64_t>) return node_type::integer;
else if constexpr (std::is_same_v<T, double>) return node_type::floating_point;
else if constexpr (std::is_same_v<T, bool>) return node_type::boolean;
else if constexpr (std::is_same_v<T, date>) return node_type::date;
else if constexpr (std::is_same_v<T, time>) return node_type::time;
else if constexpr (std::is_same_v<T, date_time>) return node_type::date_time;
}
[[nodiscard]] T& get() noexcept { return val_; }
[[nodiscard]] const T& get() const noexcept { return val_; }
};
value(const string_char*) -> value<string>;
value(string_view) -> value<string>;
value(string) -> value<string>;
value(bool) -> value<bool>;
value(float) -> value<double>;
value(double) -> value<double>;
value(int8_t) -> value<int64_t>;
value(int16_t) -> value<int64_t>;
value(int32_t) -> value<int64_t>;
value(int64_t) -> value<int64_t>;
value(uint8_t) -> value<int64_t>;
value(uint16_t) -> value<int64_t>;
value(uint32_t) -> value<int64_t>;
}

28
meson.build Normal file
View File

@ -0,0 +1,28 @@
project(
'tomlplusplus', 'cpp',
version : '0.1.0',
license : 'MIT',
default_options : [
'cpp_std=c++17',
'warning_level=3',
'cpp_eh=default'
]
)
if meson.get_compiler('cpp').get_id() == 'gcc'
add_project_arguments(['-fmax-errors=5', '-Wno-attributes'], language : 'cpp')
endif
if meson.get_compiler('cpp').get_id() == 'clang'
add_project_arguments('-ferror-limit=5', language : 'cpp')
endif
#pymod = import('python')
#python = pymod.find_installation('python3')
inc = include_directories('include')
subdir('tests')
#subdir('examples')

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
import sys
import os
import os.path
import traceback
import hashlib
import subprocess
from shutil import which
def is_tool(name):
return which(name) is not None
def get_script_folder():
return os.path.dirname(os.path.realpath(sys.argv[0]))
def read_all_text_from_file(path):
print("Reading {}".format(path))
file = open(path, 'r')
text = file.read()
file.close()
return text
def main():
hpp_path = os.path.join(get_script_folder(), '..', 'toml.hpp')
hash1 = hashlib.sha1(read_all_text_from_file(hpp_path).encode('utf-8')).hexdigest()
print("Hash 1: {}".format(hash1))
subprocess.check_call(
['py' if is_tool('py') else 'python3', 'generate_single_header.py']
)
hash2 = hashlib.sha1(read_all_text_from_file(hpp_path).encode('utf-8')).hexdigest()
print("Hash 2: {}".format(hash2))
if (hash1 != hash2):
print(
"toml.hpp wasn't up-to-date!\nRun generate_single_header.py before your commit to prevent this error.",
file=sys.stderr
)
return 1
print("toml.hpp was up-to-date")
return 0
if __name__ == '__main__':
try:
sys.exit(main())
except Exception as err:
print(
'Fatal error: [{}] {}'.format(
type(err).__name__,
str(err)
),
file=sys.stderr
)
traceback.print_exc(file=sys.stderr)
sys.exit(-1)

View File

@ -0,0 +1,137 @@
#!/usr/bin/env python3
import sys
import re
import os
import os.path
import traceback
def get_script_folder():
return os.path.dirname(os.path.realpath(sys.argv[0]))
def read_all_text_from_file(path):
print("Reading {}".format(path))
file = open(path, 'r')
text = file.read()
file.close()
return text
def make_divider(text = None, text_col = 40):
if (text is None):
return "//" + ('-' * 98)
else:
text = "//{} {} ".format('-' * (text_col - 2),text);
if (len(text) < 100):
return text + ('-' * (100 - len(text)))
else:
return text
preprocessed_include_headers = 0
preprocessed_includes = []
preprocess_include_level = -1
def preprocess(match):
global preprocessed_includes
global preprocess_include_level
global preprocessed_include_headers
raw_incl = match if isinstance(match, str) else match.group(1)
incl = raw_incl.strip().lower()
if incl in preprocessed_includes:
return ''
preprocessed_includes.append(incl)
text = read_all_text_from_file(os.path.join(get_script_folder(), '..', 'include', 'toml++', incl))
if preprocess_include_level >= 0:
text = re.sub(r'^\s*#\s*pragma\s*once\s*$', '', text, 0, re.I | re.M)
preprocess_include_level += 1
text = re.sub(r'^\s*#\s*include\s+"(.+?)"', preprocess, text, 0, re.I | re.M)
preprocess_include_level -= 1
if (preprocess_include_level == 0):
lpad = 35 + (preprocessed_include_headers % 3) * 20
preprocessed_include_headers += 1
return '''
{}
#pragma region {}
{}
#pragma endregion {}
{}'''.format(make_divider('' + raw_incl, lpad), raw_incl, text, raw_incl, make_divider('' + raw_incl, lpad))
else:
return text
def main():
# build the preamble (license etc)
preamble = []
preamble.append('''toml++
https://github.com/marzer/tomlplusplus''')
preamble.append('''*** THIS FILE WAS ASSEMBLED FROM MULTIPLE FILES PROGRAMMATICALLY - DON'T CHANGE IT DIRECTLY ***
If you wish to submit a change to toml++, hooray and thanks! But please be aware that this file
is assembled programmatically by a script and should not be edited directly. You should instead
make your changes in the relevant source file. The filenames of the source files are indicated at
the beginning and end of the relevant subregions.''')
preamble.append('''TOML language documentation:
Latest: https://github.com/toml-lang/toml
v0.5.0: https://github.com/toml-lang/toml/tree/v0.5.0''')
preamble.append(read_all_text_from_file(os.path.join(get_script_folder(), '..', 'LICENSE')))
# preprocess header(s)
source_text = preprocess('toml.h')
source_text = re.sub('\r\n', '\n', source_text, 0, re.I | re.M)
source_text = re.sub(r'^[ \t]*//[/#!].+?$', '', source_text, 0, re.I | re.M)
source_text = re.sub('\n([ \t]*\n[ \t]*)+\n', '\n\n', source_text, 0, re.I | re.M)
source_text = re.sub('([^ \t])[ \t]+\n', '\\1\n', source_text, 0, re.I | re.M)
source_text = source_text.strip()
# write the output file
output_file_path = os.path.join(get_script_folder(), '..', 'toml.hpp')
print("Writing to {}".format(output_file_path))
output_file = open(output_file_path,'w', encoding='utf-8', newline='\n')
if (len(preamble) > 0):
print(make_divider(), file=output_file)
for pre in preamble:
print('//', file=output_file)
for line in pre.splitlines():
print('//', file=output_file, end = '')
if (len(line) > 0):
print(' ', file=output_file, end = '')
print(line, file=output_file)
else:
print('\n', file=output_file, end = '')
print('//', file=output_file)
print(make_divider(), file=output_file)
print(source_text, file=output_file)
output_file.close()
if __name__ == '__main__':
try:
main()
except Exception as err:
print(
'Fatal error: [{}] {}'.format(
type(err).__name__,
str(err)
),
file=sys.stderr
)
traceback.print_exc(file=sys.stderr)
sys.exit(1)
sys.exit()

View File

@ -0,0 +1,528 @@
#!/usr/bin/env python3
import sys
import re
import os
import os.path
import math
import requests
import traceback
#### SETTINGS / MISC #########################################
class Settings:
binary_bitmasks = False
switch_case_limit = 64
def make_literal(codepoint):
if (codepoint > 0xFFFF):
return "U'\\U{:08X}'".format(codepoint)
else:
return "U'\\u{:04X}'".format(codepoint)
def make_bitmask(codepoint, size=64):
if (Settings.binary_bitmasks):
if (size==64):
return "0b{:064b}ull".format(codepoint)
else:
return "0b{:032b}u".format(codepoint)
else:
if (size==64):
return "0x{:X}ull".format(codepoint)
else:
return "0x{:X}u".format(codepoint)
def make_mask_from_indices(indices):
mask = 0
for i in indices:
mask = mask | (1 << i)
return mask;
def range_first(r):
if isinstance(r, int):
return r
else:
return r[0]
def range_last(r):
if isinstance(r, int):
return r
else:
return r[1]
def calculate_subdivisions(span_size):
# if it's a relatively small span, divide it such the effective size of each subchunk
# would be less than or equal to 64 so we'll generate bitmask ops
if (64 < span_size <= 4096):
subdiv_count = int(math.ceil(span_size / 64))
return subdiv_count
# try to find a divisor that will yield a power-of-2 size
subdiv_count = 2
subdiv_size = int(math.ceil(span_size / float(subdiv_count)))
while (subdiv_count <= Settings.switch_case_limit):
if (subdiv_size > 0 and subdiv_size < span_size and (subdiv_size & (subdiv_size-1) == 0)):
return subdiv_count
subdiv_count += 1
subdiv_size = int(math.ceil(span_size / float(subdiv_count)))
# couldn't find divisor that would yield a power-of-2 size
subdiv_count = Settings.switch_case_limit
subdiv_size = int(math.ceil(span_size / float(subdiv_count)))
while (subdiv_count > 1):
if (subdiv_size > 0 and subdiv_size < span_size):
return subdiv_count
subdiv_count -= 1
subdiv_size = int(math.ceil(span_size / float(subdiv_count)))
return subdiv_count
#### CHUNK ###################################################
class Chunk:
def __init__(self, first, last):
self.first = int(first)
self.last = int(last)
self.span_size = (self.last - self.first) + 1
self.count = 0
self.ranges = []
self.subchunks = None
self.subchunk_size = 0
self.first_set = self.last + 1
self.last_set = -1
self.first_unset = self.first
def low_range_mask(self):
if self.count == 0:
return 0;
mask = 0
bits = 0
prev_last_unset = -1
for r in self.ranges:
first = range_first(r)
last = range_last(r)
count = (last - first) + 1
while (prev_last_unset >= 0 and prev_last_unset < first and bits < 64):
prev_last_unset += 1
bits += 1
if (bits >= 64):
break;
while (count > 0 and bits < 64):
mask |= (1 << bits)
bits += 1
count -= 1
if (bits >= 64):
break;
prev_last_unset = last + 1
return mask
def add(self, first, last = None):
f = int(first)
num_added = 0
if (last is None or first == last):
self.ranges.append(f)
self.count += 1
self.last_set = max(self.last_set, f)
if (self.first_unset == f):
self.first_unset = f + 1
else:
l = int(last)
self.ranges.append((f, l))
self.count += (l - f) + 1
self.last_set = max(self.last_set, l)
if (self.first_unset == f):
self.first_unset = l + 1
self.first_set = min(self.first_set, f)
def trim(self):
if (self.subchunks is not None
or self.count == 0
or (self.first_set == self.first and self.last_set == self.last)):
return
self.first = self.first_set
self.last = self.last_set
self.span_size = (self.last - self.first) + 1
def subdivide(self):
if (self.subchunks is not None
or self.count >= self.span_size - 1
or self.count <= 1
or (self.last_set - self.first_set) + 1 <= 64
or self.count == (self.last - self.first_set) + 1
or self.count == (self.first_unset - self.first)
or self.count == (self.last_set - self.first_set) + 1
or (len(self.ranges) == 2 and range_first(self.ranges[0]) == self.first and range_last(self.ranges[1]) == self.last)
or len(self.ranges) <= 4
):
return
subchunk_count = calculate_subdivisions(self.span_size)
if (subchunk_count <= 1):
return
subchunk_size = int(math.ceil(self.span_size / float(subchunk_count)))
if (subchunk_size <= 4):
return
self.subchunks = []
self.subchunk_size = subchunk_size
for subchunk in range(subchunk_count):
self.subchunks.append(
Chunk(
self.first + (subchunk * self.subchunk_size),
min(self.first + (((subchunk + 1) * self.subchunk_size) - 1), self.last)
)
)
for r in self.ranges:
if (isinstance(r, int)):
subchunk = int((r - self.first) / self.subchunk_size)
self.subchunks[subchunk].add(r)
else:
start_chunk = int((r[0] - self.first) / self.subchunk_size)
end_chunk = int((r[1] - self.first) / self.subchunk_size)
for subchunk in range(start_chunk, end_chunk+1):
self.subchunks[subchunk].add(
max(r[0], self.subchunks[subchunk].first),
min(r[1], self.subchunks[subchunk].last),
)
#self.ranges = None
for subchunk in self.subchunks:
subchunk.trim()
subchunk.subdivide()
def always_returns_true(self):
return self.count == self.span_size;
def always_returns_false(self):
return self.count == 0;
def print_subchunk_case(self, subchunk_index, output_file, level, indent):
print("{}\tcase {}: ".format(indent, subchunk_index), end='', file=output_file)
if (self.subchunks[subchunk_index].count == self.subchunks[subchunk_index].span_size):
self.subchunks[subchunk_index].print(output_file, level + 1, (self.first, self.last))
else:
if (self.subchunks[subchunk_index].subchunks is not None and self.subchunks[subchunk_index].span_size > 64):
print("\n{}\t{{".format(indent), file=output_file)
self.subchunks[subchunk_index].print(output_file, level + 1, (self.first, self.last))
if (self.subchunks[subchunk_index].subchunks is not None and self.subchunks[subchunk_index].span_size > 64):
print("{}\t}}".format(indent), file=output_file)
def return_value_string(self):
# return true; (completely full range)
if (self.always_returns_true()):
return 'true';
# return false; (completely empty range)
elif (self.always_returns_false()):
return 'false';
# return cp == A
elif (self.count == 1):
return 'codepoint == {}'.format(make_literal(self.ranges[0]))
# return cp != A
elif (self.count == self.span_size - 1):
return 'codepoint != {}'.format(make_literal(self.first_unset))
# return cp < A
elif (self.count == (self.first_unset - self.first)):
return 'codepoint < {}'.format(make_literal(self.first_unset))
# return cp >= A
elif (self.count == (self.last - self.first_set) + 1):
return 'codepoint >= {}'.format(make_literal(self.first_set))
# return cp >= A && cp <= B
elif (self.count == (self.last_set - self.first_set) + 1):
return 'codepoint >= {} && codepoint <= {}'.format(make_literal(self.first_set), make_literal(self.last_set))
# return cp <= A || cp >= B
elif (len(self.ranges) == 2 and range_first(self.ranges[0]) == self.first and range_last(self.ranges[1]) == self.last):
return 'codepoint <= {} || codepoint >= {}'.format(make_literal(range_last(self.ranges[0])), make_literal(range_first(self.ranges[1])))
# return cp & A (32-bit)
elif ((self.last_set - self.first_set) + 1 <= 32):
if (self.first_set == self.first):
return '(1u << (static_cast<uint_least32_t>(codepoint) - 0x{:X}u)) & {}'.format(self.first_set, make_bitmask(self.low_range_mask(), 32))
else:
return 'codepoint >= {} && ((1u << (static_cast<uint_least32_t>(codepoint) - 0x{:X}u)) & {})'.format(
make_literal(self.first_set), self.first_set, make_bitmask(self.low_range_mask(), 32))
# return cp & A (64-bit)
elif ((self.last_set - self.first_set) + 1 <= 64):
if (self.first_set == self.first):
return '(1ull << (static_cast<uint_least64_t>(codepoint) - 0x{:X}ull)) & {}'.format(self.first_set, make_bitmask(self.low_range_mask()))
else:
return 'codepoint >= {} && ((1ull << (static_cast<uint_least64_t>(codepoint) - 0x{:X}ull)) & {})'.format(
make_literal(self.first_set), self.first_set, make_bitmask(self.low_range_mask()))
return None
def print(self, output_file, level = 0, parent_range = None):
indent = '\t\t' + ('\t' * (2 * level))
if (parent_range is None):
parent_range = (0, 0x7FFFFFFF)
rvs = self.return_value_string()
# return ______;
if (rvs is not None):
print("return {};".format(rvs), file=output_file)
# switch (cp)
elif (self.subchunks is not None):
# guard against non-exhaustive ranges (we may have been trimmed)
if (self.first > parent_range[0] and self.last < parent_range[1]):
print("{}if (codepoint < {} || codepoint > {})\n{}\treturn false;\n".format(indent, make_literal(self.first), make_literal(self.last), indent), file=output_file)
elif (self.first > parent_range[0]):
print("{}if (codepoint < {})\n{}\treturn false;\n".format(indent, make_literal(self.first), indent), file=output_file)
elif (self.last < parent_range[1]):
print("{}if (codepoint > {})\n{}\treturn false;\n".format(indent, make_literal(self.last), indent), file=output_file)
# see if we can avoid emitting a switch altogether, or reduce its scope
always_true = []
always_false = []
not_always_true_or_false = []
for subchunk_index in range(len(self.subchunks)):
even = (subchunk_index % 2) == 0
if self.subchunks[subchunk_index].always_returns_true():
always_true.append(subchunk_index)
elif self.subchunks[subchunk_index].always_returns_false():
always_false.append(subchunk_index)
else:
not_always_true_or_false.append(subchunk_index)
selector = '(static_cast<uint_least32_t>(codepoint) - 0x{:X}u) / {}u'.format(self.first, self.subchunk_size)
# return selector & mask
if (len(always_true) + len(always_false) == len(self.subchunks) and len(self.subchunks) <= 64):
print("{}return ({}) & {};".format(indent, selector, make_bitmask(make_mask_from_indices(always_true))), file=output_file)
# return selector == A ? true : selector & mask
#elif (len(not_always_true_or_false) == 1
# and (len(always_true) + len(always_false)) == len(self.subchunks)-1
# and len(self.subchunks) <= 64):
# print('{}const auto selector = {}; //kek'.format(indent, selector), file=output_file)
# print('{}return selector == {}u ? true : selector & {};'.format(
# indent,
# not_always_true_or_false[0],
# make_bitmask(make_mask_from_indices(always_true))
# ),
# file=output_file
# )
# switch(selector)
else:
print("{}TOML_ASSUME_CODEPOINT_BETWEEN({}, {});".format(indent, make_literal(self.first), make_literal(self.last)), file=output_file)
print("{}switch ({})\n{}{{".format(indent, selector, indent), file=output_file)
if (len(always_true) == 0 and len(always_false) == 0):
for subchunk_index in range(len(self.subchunks)):
self.print_subchunk_case(subchunk_index, output_file, level, indent)
print("{}\tTOML_NO_DEFAULT_CASE;".format(indent), file=output_file)
elif (len(always_true) > len(always_false)):
for subchunk_index in range(len(self.subchunks)):
if not self.subchunks[subchunk_index].always_returns_true():
self.print_subchunk_case(subchunk_index, output_file, level, indent)
print("{}\tdefault: return true;".format(indent), file=output_file)
else:
for subchunk_index in range(len(self.subchunks)):
if not self.subchunks[subchunk_index].always_returns_false():
self.print_subchunk_case(subchunk_index, output_file, level, indent)
print("{}\tdefault: return false;".format(indent), file=output_file)
print("{}}}".format(indent), file=output_file)
print("{}// chunk summary: {} codepoints from {} ranges (spanning a search area of {})".format(indent, self.count, len(self.ranges), self.span_size), file=output_file)
# return cp == A || cp == B ...
else:
print("return", end='', file=output_file)
line_weight = 0
first_line = True
for range_idx in range(0, len(self.ranges)):
r = self.ranges[range_idx]
range_weight = (1 if (
isinstance(r, int)
or (range_idx == 0 and r[0] == self.first)
or (range_idx == (len(self.ranges)-1) and r[1] == self.last))
else 2
)
needs_space = True
if ((line_weight + range_weight) > (4 - (1 if first_line else 0))):
print("\n\t{}".format(indent), end='', file=output_file)
line_weight = range_weight
needs_space = False
first_line = False
else:
line_weight += range_weight
if (needs_space):
print(" ", end='', file=output_file)
if (range_idx > 0):
print("|| ", end='', file=output_file)
if (isinstance(r, int)):
print("codepoint == {}".format(make_literal(r)), end='', file=output_file)
elif (range_idx == 0 and r[0] == self.first):
print("codepoint <= {}".format(make_literal(r[1])), end='', file=output_file)
elif (range_idx == (len(self.ranges)-1) and r[1] == self.last):
print("codepoint >= {}".format(make_literal(r[0])), end='', file=output_file)
else:
print("{}codepoint >= {} && codepoint <= {}{}".format(
'(' if len(self.ranges) > 1 else '',
make_literal(r[0]),
make_literal(r[1]),
')' if len(self.ranges) > 1 else ''
),
end='',
file=output_file
)
print(";", file=output_file)
#### FUNCTION GENERATOR #####################################
def emit_function(name, categories, file, codepoints):
# divide the codepoints up into chunks of ranges
root_chunk = Chunk(codepoints[0][0], codepoints[-1][0])
first_codepoint = -1
last_codepoint = -1
for codepoint, category in codepoints:
if (category in categories):
if (first_codepoint == -1):
first_codepoint = codepoint
last_codepoint = codepoint
elif (last_codepoint == codepoint-1):
last_codepoint = codepoint
else:
root_chunk.add(first_codepoint, last_codepoint)
first_codepoint = codepoint
last_codepoint = codepoint
if (first_codepoint != -1):
root_chunk.add(first_codepoint, last_codepoint)
root_chunk.trim()
root_chunk.subdivide()
# write the function
print('\n\t/// \\brief Returns true if a codepoint belongs to any of these categories: {}'.format(', '.join(categories)), file=file)
print('\t[[nodiscard]]', file=file)
print('\tconstexpr bool {}(char32_t codepoint) noexcept\n\t{{'.format(name), file=file)
root_chunk.print(file)
print('\t}', file=file)
#### MAIN ####################################################
def get_script_folder():
return os.path.dirname(os.path.realpath(sys.argv[0]))
def main():
# get unicode character database
codepoint_list = ''
codepoint_file_path = os.path.join(get_script_folder(), 'UnicodeData.txt')
if (not os.path.exists(codepoint_file_path)):
print("Couldn't find unicode database file, will download")
response = requests.get(
'https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt',
timeout=1
)
codepoint_list = response.text
codepoint_file = open(codepoint_file_path, 'w', newline='\n')
print(codepoint_list, end='', file=codepoint_file)
codepoint_file.close()
else:
print("Reading unicode database file into memory")
codepoint_file = open(codepoint_file_path, 'r')
codepoint_list = codepoint_file.read()
codepoint_file.close()
# parse the database file into codepoints
re_codepoint = re.compile(r'^([0-9a-fA-F]+);(.+?);([a-zA-Z]+);')
current_range_start = -1
codepoints = []
for codepoint_entry in codepoint_list.split('\n'):
match = re_codepoint.search(codepoint_entry)
if (match is None):
if (current_range_start > -1):
raise Exception('Previous codepoint indicated the start of a range but the next one was null')
continue
codepoint = int('0x{}'.format(match.group(1)), 16)
if (codepoint <= 128): # ASCII range is handled separately
continue
if (current_range_start > -1):
for cp in range(current_range_start, codepoint):
codepoints.append((cp, match.group(3)))
current_range_start = -1
else:
if (match.group(2).endswith(', First>')):
current_range_start = codepoint
else:
codepoints.append((codepoint, match.group(3)))
print("Parsed {} codepoints from unicode database file.".format(len(codepoints)))
codepoints.sort(key=lambda r:r[0])
# write the output file
output_file_path = os.path.join(get_script_folder(), '..', 'include', 'toml++', 'toml_utf8_generated.h')
print("Writing to {}".format(output_file_path))
output_file = open(output_file_path, 'w', newline='\n')
print('//# this file was generated by generate_unicode_functions.py', file=output_file)
print('#pragma once', file=output_file)
print('#include "toml_common.h"', file=output_file)
print('\n#define TOML_ASSUME_CODEPOINT_BETWEEN(first, last)\t\\\n\tTOML_ASSUME(codepoint >= first);\t\t\t\t\\\n\tTOML_ASSUME(codepoint <= last)', file=output_file)
print('\nnamespace toml::impl\n{', file=output_file, end='')
emit_function('is_unicode_letter', ('Ll', 'Lm', 'Lo', 'Lt', 'Lu'), output_file, codepoints)
emit_function('is_unicode_number', ('Nd', 'Nl'), output_file, codepoints)
emit_function('is_unicode_combining_mark', ('Mn', 'Mc'), output_file, codepoints)
print('}\n\n#undef TOML_ASSUME_CODEPOINT_BETWEEN', file=output_file)
output_file.close()
if __name__ == '__main__':
try:
main()
except Exception as err:
print(
'Fatal error: [{}] {}'.format(
type(err).__name__,
str(err)
),
file=sys.stderr
)
traceback.print_exc(file=sys.stderr)
sys.exit(1)
sys.exit()

1
tests/catch2 Submodule

@ -0,0 +1 @@
Subproject commit d10b9bd02e098476670f5eb0527d2c7281476e8a

55
tests/catch2.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
//catch config
#define CATCH_CONFIG_CPP11_TO_STRING
#define CATCH_CONFIG_CPP17_OPTIONAL
#define CATCH_CONFIG_CPP17_STRING_VIEW
#define CATCH_CONFIG_FAST_COMPILE
#define CATCH_CONFIG_CONSOLE_WIDTH 100
//windows.h config
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOATOM // - Atom Manager routines
#define NOBITMAP
#define NOCLIPBOARD // - Clipboard routines
#define NOCOLOR // - Screen colors
#define NOCOMM // - COMM driver routines
#define NOCTLMGR // - Control and Dialog routines
#define NODEFERWINDOWPOS // - DeferWindowPos routines
#define NODRAWTEXT // - DrawText() and DT_*
#define NOGDI // - All GDI defines and routines
#define NOGDICAPMASKS // - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
#define NOHELP // - Help engine interface.
#define NOICONS // - IDI_*
#define NOKANJI // - Kanji support stuff.
#define NOKEYSTATES // - MK_*
#define NOKERNEL // - All KERNEL defines and routines
#define NOMB // - MB_* and MessageBox()
#define NOMCX // - Modem Configuration Extensions
#define NOMENUS // - MF_*
#define NOMEMMGR // - GMEM_*, LMEM_*, GHND, LHND, associated routines
#define NOMETAFILE // - typedef METAFILEPICT
#define NOMINMAX // - Macros min(a,b) and max(a,b)
#define NOMSG // - typedef MSG and associated routines
#define NONLS // - All NLS defines and routines
#define NOOPENFILE // - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOPROFILER // - Profiler interface.
#define NORASTEROPS // - Binary and Tertiary raster ops
#define NOSCROLL // - SB_* and scrolling routines
#define NOSERVICE // - All Service Controller routines, SERVICE_ equates, etc.
#define NOSHOWWINDOW // - SW_*
#define NOSOUND // - Sound driver routines
#define NOSYSCOMMANDS // - SC_*
#define NOSYSMETRICS // - SM_*
#define NOTEXTMETRIC // - typedef TEXTMETRIC and associated routines
#define NOUSER // - All USER defines and routines
#define NOVIRTUALKEYCODES // - VK_*
#define NOWH // - SetWindowsHook and WH_*
#define NOWINOFFSETS // - GWL_*, GCL_*, associated routines
#define NOWINMESSAGES // - WM_*, EM_*, LB_*, CB_*
#define NOWINSTYLES // - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
#endif
#include <catch2/single_include/catch2/catch.hpp>

40
tests/lifetimes.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "tests.h"
TEST_CASE("lifetime - tables")
{
static constexpr auto filename = "foo.toml"sv;
parsing_should_succeed(
S(R"(test = { val1 = "foo" })"sv),
[&](table&& tbl) noexcept
{
CHECK(tbl.region().begin == source_position{ 1, 1 });
CHECK(tbl.region().end == source_position{ 1, 25 });
CHECK(tbl.region().path);
CHECK(*tbl.region().path == filename);
CHECK(tbl.size() == 1_sz);
REQUIRE(tbl[S("test")].as<table>());
CHECK(tbl[S("test")].as<table>()->size() == 1_sz);
CHECK(tbl[S("test")][S("val1")] == S("foo"sv));
table test_table;
CHECK(test_table.region().begin == source_position{});
CHECK(test_table.region().end == source_position{});
CHECK(!test_table.region().path);
CHECK(test_table.size() == 0_sz);
CHECK(!test_table[S("test")].as<table>());
test_table = std::move(tbl);
CHECK(test_table.region().begin == source_position{ 1, 1 });
CHECK(test_table.region().end == source_position{ 1, 25 });
CHECK(test_table.region().path);
CHECK(*test_table.region().path == filename);
CHECK(test_table.size() == 1_sz);
REQUIRE(test_table[S("test")].as<table>());
CHECK(test_table[S("test")].as<table>()->size() == 1_sz);
CHECK(test_table[S("test")][S("val1")] == S("foo"sv));
},
filename
);
}

11
tests/main.cpp Normal file
View File

@ -0,0 +1,11 @@
#define CATCH_CONFIG_RUNNER
#include "catch2.h"
int main(int argc, char* argv[])
{
#ifdef _WIN32
SetConsoleOutputCP(65001);
#endif
return Catch::Session().run(argc, argv);;
}

73
tests/meson.build Normal file
View File

@ -0,0 +1,73 @@
test_sources = [
'lifetimes.cpp',
'main.cpp',
'parsing_arrays.cpp',
'parsing_booleans.cpp',
'parsing_comments.cpp',
'parsing_dates_and_times.cpp',
'parsing_floats.cpp',
'parsing_integers.cpp',
'parsing_key_value_pairs.cpp',
'parsing_spec_example.cpp',
'parsing_strings.cpp',
'parsing_tables.cpp'
]
disable_exceptions = 'cpp_eh=none'
no_unreleased_features = '-DTOML_UNRELEASED_FEATURES=0'
test_char = executable(
'test_char',
test_sources,
include_directories : inc
)
test('test_char', test_char)
test_char_noexcept = executable(
'test_char_noexcept',
test_sources,
include_directories : inc,
override_options : [ disable_exceptions ]
)
test('test_char_noexcept', test_char_noexcept)
test_strict_char = executable(
'test_strict_char',
test_sources,
include_directories : inc,
cpp_args : [ no_unreleased_features ]
)
test('test_strict_char', test_strict_char)
test_strict_char_noexcept = executable(
'test_strict_char_noexcept',
test_sources,
include_directories : inc,
override_options : [ disable_exceptions ],
cpp_args : [ no_unreleased_features ]
)
test('test_strict_char_noexcept', test_strict_char_noexcept)
# char8_t is not supported until gcc9, yo.
# test_char8 = executable(
# 'test_char8',
# test_sources,
# include_directories : inc,
# cpp_args : ['-DTOML_CHAR_8_STRINGS=1', '-fchar8_t']
#)
#
# test_char8_noexcept = executable(
# 'test_char8_noexcept',
# test_sources,
# include_directories : inc,
# override_options : [ disable_exceptions ],
# cpp_args : ['-DTOML_CHAR_8_STRINGS=1', '-fchar8_t']
#)

140
tests/parsing_arrays.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "tests.h"
TEST_CASE("parsing arrays")
{
parsing_should_succeed(S(R"(
integers = [ 1, 2, 3 ]
integers2 = [
1, 2, 3
]
integers3 = [
1,
2, # this is ok
]
colors = [ "red", "yellow", "green" ]
nested_array_of_int = [ [ 1, 2 ], [3, 4, 5] ]
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
string_array = [ "all", 'strings', """are the same""", '''type''' ]
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("integers")].as<array>());
CHECK(tbl[S("integers")].as<array>()->is_homogeneous());
CHECK(tbl[S("integers")].as<array>()->size() == 3);
CHECK(tbl[S("integers")][0] == 1);
CHECK(tbl[S("integers")][1] == 2);
CHECK(tbl[S("integers")][2] == 3);
REQUIRE(tbl[S("integers2")].as<array>());
CHECK(tbl[S("integers2")].as<array>()->is_homogeneous());
CHECK(tbl[S("integers2")].as<array>()->size() == 3);
CHECK(tbl[S("integers2")][0] == 1);
CHECK(tbl[S("integers2")][1] == 2);
CHECK(tbl[S("integers2")][2] == 3);
REQUIRE(tbl[S("integers3")].as<array>());
CHECK(tbl[S("integers3")].as<array>()->is_homogeneous());
CHECK(tbl[S("integers3")].as<array>()->size() == 2);
CHECK(tbl[S("integers3")][0] == 1);
CHECK(tbl[S("integers3")][1] == 2);
REQUIRE(tbl[S("colors")].as<array>());
CHECK(tbl[S("colors")].as<array>()->is_homogeneous());
CHECK(tbl[S("colors")].as<array>()->size() == 3);
CHECK(tbl[S("colors")][0] == S("red"sv));
CHECK(tbl[S("colors")][1] == S("yellow"sv));
CHECK(tbl[S("colors")][2] == S("green"sv));
REQUIRE(tbl[S("nested_array_of_int")].as<array>());
CHECK(tbl[S("nested_array_of_int")].as<array>()->is_homogeneous());
CHECK(tbl[S("nested_array_of_int")].as<array>()->size() == 2);
REQUIRE(tbl[S("nested_array_of_int")][0].as<array>());
CHECK(tbl[S("nested_array_of_int")][0].as<array>()->is_homogeneous());
CHECK(tbl[S("nested_array_of_int")][0].as<array>()->size() == 2);
CHECK(tbl[S("nested_array_of_int")][0][0] == 1);
CHECK(tbl[S("nested_array_of_int")][0][1] == 2);
REQUIRE(tbl[S("nested_array_of_int")][1].as<array>());
CHECK(tbl[S("nested_array_of_int")][1].as<array>()->is_homogeneous());
CHECK(tbl[S("nested_array_of_int")][1].as<array>()->size() == 3);
CHECK(tbl[S("nested_array_of_int")][1][0] == 3);
CHECK(tbl[S("nested_array_of_int")][1][1] == 4);
CHECK(tbl[S("nested_array_of_int")][1][2] == 5);
REQUIRE(tbl[S("nested_mixed_array")].as<array>());
CHECK(tbl[S("nested_mixed_array")].as<array>()->is_homogeneous());
CHECK(tbl[S("nested_mixed_array")].as<array>()->size() == 2);
REQUIRE(tbl[S("nested_mixed_array")][0].as<array>());
CHECK(tbl[S("nested_mixed_array")][0].as<array>()->is_homogeneous());
CHECK(tbl[S("nested_mixed_array")][0].as<array>()->size() == 2);
CHECK(tbl[S("nested_mixed_array")][0][0] == 1);
CHECK(tbl[S("nested_mixed_array")][0][1] == 2);
REQUIRE(tbl[S("nested_mixed_array")][1].as<array>());
CHECK(tbl[S("nested_mixed_array")][1].as<array>()->is_homogeneous());
CHECK(tbl[S("nested_mixed_array")][1].as<array>()->size() == 3);
CHECK(tbl[S("nested_mixed_array")][1][0] == S("a"sv));
CHECK(tbl[S("nested_mixed_array")][1][1] == S("b"sv));
CHECK(tbl[S("nested_mixed_array")][1][2] == S("c"sv));
REQUIRE(tbl[S("string_array")].as<array>());
CHECK(tbl[S("string_array")].as<array>()->is_homogeneous());
CHECK(tbl[S("string_array")].as<array>()->size() == 4);
CHECK(tbl[S("string_array")][0] == S("all"sv));
CHECK(tbl[S("string_array")][1] == S("strings"sv));
CHECK(tbl[S("string_array")][2] == S("are the same"sv));
CHECK(tbl[S("string_array")][3] == S("type"sv));
REQUIRE(tbl[S("integers")].as<array>());
CHECK(tbl[S("integers")].as<array>()->is_homogeneous());
CHECK(tbl[S("integers")].as<array>()->size() == 3);
CHECK(tbl[S("integers")][0] == 1);
CHECK(tbl[S("integers")][1] == 2);
CHECK(tbl[S("integers")][2] == 3);
}
);
// heterogeneous arrays are allowed after 0.5.0
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
parsing_should_succeed(S(R"(
# Mixed-type arrays are allowed
numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contributors = [
"Foo Bar <foo@example.com>",
{ name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
]
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("numbers")].as<array>());
CHECK(!tbl[S("numbers")].as<array>()->is_homogeneous());
CHECK(tbl[S("numbers")].as<array>()->size() == 6);
CHECK(tbl[S("numbers")][0].as<double>());
CHECK(tbl[S("numbers")][1].as<double>());
CHECK(tbl[S("numbers")][2].as<double>());
CHECK(tbl[S("numbers")][3].as<int64_t>());
CHECK(tbl[S("numbers")][4].as<int64_t>());
CHECK(tbl[S("numbers")][5].as<int64_t>());
CHECK(tbl[S("numbers")][0] == 0.1);
CHECK(tbl[S("numbers")][1] == 0.2);
CHECK(tbl[S("numbers")][2] == 0.5);
CHECK(tbl[S("numbers")][3] == 1);
CHECK(tbl[S("numbers")][4] == 2);
CHECK(tbl[S("numbers")][5] == 5);
REQUIRE(tbl[S("contributors")].as<array>());
CHECK(!tbl[S("contributors")].as<array>()->is_homogeneous());
CHECK(tbl[S("contributors")].as<array>()->size() == 2);
CHECK(tbl[S("contributors")][0].as<string>());
CHECK(tbl[S("contributors")][1].as<table>());
CHECK(tbl[S("contributors")][0] == S("Foo Bar <foo@example.com>"sv));
CHECK(tbl[S("contributors")][1][S("name")] == S("Baz Qux"sv));
CHECK(tbl[S("contributors")][1][S("email")] == S("bazqux@example.com"sv));
CHECK(tbl[S("contributors")][1][S("url")] == S("https://example.com/bazqux"sv));
}
);
#else
parsing_should_fail(S("numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]"sv));
#endif
}

View File

@ -0,0 +1,27 @@
#include "tests.h"
TEST_CASE("parsing booleans")
{
parsing_should_succeed(S(R"(
bool1 = true
bool2 = false
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("bool1")] == true);
CHECK(tbl[S("bool2")] == false);
}
);
// "Always lowercase."
parsing_should_fail(S("bool = True"sv));
parsing_should_fail(S("bool = TRUE"sv));
parsing_should_fail(S("bool = tRUE"sv));
parsing_should_fail(S("bool = False"sv));
parsing_should_fail(S("bool = FALSE"sv));
parsing_should_fail(S("bool = fALSE"sv));
// value tests
parse_expected_value(" true", true);
parse_expected_value("false", false);
}

View File

@ -0,0 +1,17 @@
#include "tests.h"
TEST_CASE("parsing comments")
{
parsing_should_succeed(S(R"(
# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment"
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 2);
CHECK(tbl[S("key")] == S("value"sv));
CHECK(tbl[S("another")] == S("# This is not a comment"sv));
}
);
}

View File

@ -0,0 +1,43 @@
#include "tests.h"
TOML_PUSH_WARNINGS
TOML_DISABLE_FIELD_INIT_WARNING
TEST_CASE("parsing dates and times")
{
parsing_should_succeed(S(R"(
odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00
odt4 = 1979-05-27 07:32:00Z
ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999
ld1 = 1979-05-27
lt1 = 07:32:00
lt2 = 00:32:00.999999
)"sv),
[](table&& tbl) noexcept
{
static constexpr auto odt1 = date_time{ { 1979, 5, 27 }, { 7, 32 }, time_offset{} };
CHECK(tbl[S("odt1")] == odt1);
static constexpr auto odt2 = date_time{ { 1979, 5, 27 }, { 0, 32 }, time_offset{ -7 } };
CHECK(tbl[S("odt2")] == odt2);
static constexpr auto odt3 = date_time{ { 1979, 5, 27 }, { 0, 32, 0, 999999000u }, time_offset{ -7 } };
CHECK(tbl[S("odt3")] == odt3);
static constexpr auto odt4 = date_time{ { 1979, 5, 27 }, { 7, 32 }, time_offset{} };
CHECK(tbl[S("odt4")] == odt4);
static constexpr auto ldt1 = date_time{ { 1979, 5, 27 }, { 7, 32 } };
CHECK(tbl[S("ldt1")] == ldt1);
static constexpr auto ldt2 = date_time{ { 1979, 5, 27 }, { 0, 32, 0, 999999000u } };
CHECK(tbl[S("ldt2")] == ldt2);
static constexpr auto ld1 = date{ 1979, 5, 27 };
CHECK(tbl[S("ld1")] == ld1);
static constexpr auto lt1 = toml::time{ 7, 32 };
CHECK(tbl[S("lt1")] == lt1);
static constexpr auto lt2 = toml::time{ 0, 32, 0, 999999000u };
CHECK(tbl[S("lt2")] == lt2);
}
);
}
TOML_POP_WARNINGS

112
tests/parsing_floats.cpp Normal file
View File

@ -0,0 +1,112 @@
#include "tests.h"
TEST_CASE("parsing floats - normal")
{
parsing_should_succeed(S(R"(
# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
# exponent
flt4 = 5e+22
flt5 = 1e06
flt6 = -2E-2
# both
flt7 = 6.626e-34
flt8 = 224_617.445_991_228
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("flt1")] == 1.0);
CHECK(tbl[S("flt2")] == 3.1415);
CHECK(tbl[S("flt3")] == -0.01);
CHECK(tbl[S("flt4")].as<double>()->get() == 5e+22_a);
CHECK(tbl[S("flt5")].as<double>()->get() == 1e6_a);
CHECK(tbl[S("flt6")] == -2E-2);
CHECK(tbl[S("flt7")].as<double>()->get() == 6.626e-34_a);
CHECK(tbl[S("flt8")].as<double>()->get() == 224617.445991228_a);
}
);
// "Each underscore must be surrounded by at least one digit on each side."
parsing_should_fail(S("flt8 = 224_617.445_991_228_"sv));
parsing_should_fail(S("flt8 = _224_617.445_991_228"sv));
parsing_should_fail(S("flt8 = 224__617.445_991_228"sv));
// "Float values -0.0 and +0.0 are valid and should map according to IEEE 754."
parsing_should_succeed(
S(R"(zeroes = [-0.0, +0.0])"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("zeroes")][0] == -0.0);
CHECK(tbl[S("zeroes")][1] == +0.0);
}
);
//value tests
parse_expected_value( "1.0"sv, 1.0 );
parse_expected_value( "0.1"sv, 0.1 );
parse_expected_value( "0.001"sv, 0.001 );
parse_expected_value( "0.100"sv, 0.1 );
parse_expected_value( "+3.14"sv, 3.14 );
parse_expected_value( "-3.14"sv, -3.14 );
parse_expected_value( "3.1415_9265_3589"sv, 3.141592653589 );
parse_expected_value( "+3.1415_9265_3589"sv, 3.141592653589 );
parse_expected_value( "-3.1415_9265_3589"sv, -3.141592653589 );
parse_expected_value( "123_456.789"sv, 123456.789 );
parse_expected_value( "+123_456.789"sv, 123456.789 );
parse_expected_value( "-123_456.789"sv, -123456.789 );
parse_expected_value( "+0.0"sv, 0.0 );
parse_expected_value( "-0.0"sv, -0.0 );
parse_expected_value( "1e10"sv, 1e10 );
parse_expected_value( "1e+10"sv, 1e10 );
parse_expected_value( "1e-10"sv, 1e-10 );
parse_expected_value( "+1e10"sv, 1e10 );
parse_expected_value( "+1e+10"sv, 1e10 );
parse_expected_value( "+1e-10"sv, 1e-10 );
parse_expected_value( "-1e10"sv, -1e10 );
parse_expected_value( "-1e+10"sv, -1e10 );
parse_expected_value( "-1e-10"sv, -1e-10 );
parse_expected_value( "123e-10"sv, 123e-10 );
parse_expected_value( "1E10"sv, 1e10 );
parse_expected_value( "1E+10"sv, 1e10 );
parse_expected_value( "1E-10"sv, 1e-10 );
parse_expected_value( "123E-10"sv, 123e-10 );
parse_expected_value( "1_2_3E-10"sv, 123e-10 );
parse_expected_value( "1_2_3E-1_0"sv, 123e-10 );
parse_expected_value( "+0e0"sv, 0.0 );
parse_expected_value( "-0e0"sv, -0.0 );
parse_expected_value( "1_2_3E-01"sv, 123e-1 );
parse_expected_value( "1_2_3E-0_1"sv, 123e-1 );
parse_expected_value( "6.02e23"sv, 6.02e23 );
parse_expected_value( "6.02e+23"sv, 6.02e23 );
parse_expected_value( "1.112_650_06e-17"sv, 1.11265006e-17 );
}
TEST_CASE("parsing floats - inf and nan")
{
parsing_should_succeed(S(R"(
# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation specific
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("sf1")] == std::numeric_limits<double>::infinity());
CHECK(tbl[S("sf2")] == std::numeric_limits<double>::infinity());
CHECK(tbl[S("sf3")] == -std::numeric_limits<double>::infinity());
CHECK(std::isnan(tbl[S("sf4")].as<double>()->get()));
CHECK(std::isnan(tbl[S("sf5")].as<double>()->get()));
CHECK(std::isnan(tbl[S("sf6")].as<double>()->get()));
}
);
}

151
tests/parsing_integers.cpp Normal file
View File

@ -0,0 +1,151 @@
#include "tests.h"
TEST_CASE("parsing integers - decimal")
{
parsing_should_succeed(S(R"(
int1 = +99
int2 = 42
int3 = 0
int4 = -17
int5 = 1_000
int6 = 5_349_221
int7 = 1_2_3_4_5 # VALID but discouraged
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("int1")] == 99);
CHECK(tbl[S("int2")] == 42);
CHECK(tbl[S("int3")] == 0);
CHECK(tbl[S("int4")] == -17);
CHECK(tbl[S("int5")] == 1000);
CHECK(tbl[S("int6")] == 5349221);
CHECK(tbl[S("int7")] == 12345);
}
);
// "Each underscore must be surrounded by at least one digit on each side."
parsing_should_fail(S("int5 = 1__000"sv));
parsing_should_fail(S("int5 = _1_000"sv));
parsing_should_fail(S("int5 = 1_000_"sv));
// "Leading zeroes are not allowed."
parsing_should_fail(S("int1 = +099"sv));
parsing_should_fail(S("int2 = 042"sv));
parsing_should_fail(S("int3 = 00"sv));
parsing_should_fail(S("int4 = -017"sv));
parsing_should_fail(S("int5 = 01_000"sv));
parsing_should_fail(S("int6 = 05_349_221"sv));
parsing_should_fail(S("int7 = 01_2_3_4_5"sv));
// "Integer values -0 and +0 are valid and identical to an unprefixed zero."
parsing_should_succeed(
S("zeroes = [-0, +0]"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("zeroes")][0] == 0);
CHECK(tbl[S("zeroes")][1] == 0);
}
);
parsing_should_fail(S("val = +-1"sv));
parsing_should_fail(S("val = -+1"sv));
parsing_should_fail(S("val = ++1"sv));
parsing_should_fail(S("val = --1"sv));
parsing_should_fail(S("val = 1-"sv));
parsing_should_fail(S("val = 1+"sv));
parsing_should_fail(S("val = -1+"sv));
parsing_should_fail(S("val = +1-"sv));
// value tests
parse_expected_value( "1234"sv, 1234 );
parse_expected_value( "+1234"sv, 1234 );
parse_expected_value( "-1234"sv, -1234 );
parse_expected_value( "0"sv, 0 );
parse_expected_value( "1_2_3_4"sv, 1234 );
parse_expected_value( "+1_2_3_4"sv, 1234 );
parse_expected_value( "-1_2_3_4"sv, -1234 );
parse_expected_value( "123_456_789"sv, 123456789 );
}
TEST_CASE("parsing integers - hex, bin, oct")
{
parsing_should_succeed(S(R"(
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("hex1")] == 0xDEADBEEF);
CHECK(tbl[S("hex2")] == 0xDEADBEEF);
CHECK(tbl[S("hex3")] == 0xDEADBEEF);
CHECK(tbl[S("oct1")] == 01234567);
CHECK(tbl[S("oct2")] == 0755);
CHECK(tbl[S("bin1")] == 0b11010110);
}
);
// "leading + is not allowed"
parsing_should_fail(S("hex1 = +0xDEADBEEF"sv));
parsing_should_fail(S("hex2 = +0xdeadbeef"sv));
parsing_should_fail(S("hex3 = +0xdead_beef"sv));
parsing_should_fail(S("oct1 = +0o01234567"sv));
parsing_should_fail(S("oct2 = +0o7550"sv));
parsing_should_fail(S("int6 = +05_349_221"sv));
parsing_should_fail(S("bin1 = +0b11010110"sv));
// "leading zeros are allowed (after the prefix)"
parsing_should_succeed(S(R"(
hex1 = 0x000DEADBEEF
hex2 = 0x00000deadbeef
hex3 = 0x0dead_beef
oct1 = 0o0001234567
oct2 = 0o000755
bin1 = 0b0000011010110
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("hex1")] == 0xDEADBEEF);
CHECK(tbl[S("hex2")] == 0xDEADBEEF);
CHECK(tbl[S("hex3")] == 0xDEADBEEF);
CHECK(tbl[S("oct1")] == 01234567);
CHECK(tbl[S("oct2")] == 0755);
CHECK(tbl[S("bin1")] == 0b11010110);
}
);
// "64 bit (signed long) range expected (9,223,372,036,854,775,808 to 9,223,372,036,854,775,807)."
parsing_should_fail(S("val = 9223372036854775809"sv));
parsing_should_fail(S("val = 9223372036854775808"sv));
// "***Non-negative*** integer values may also be expressed in hexadecimal, octal, or binary"
parsing_should_fail(S("val = -0o1"sv));
parsing_should_fail(S("val = -0b1"sv));
parsing_should_fail(S("val = -0x1"sv));
// value tests
parse_expected_value( "0xDEADBEEF"sv, 0xDEADBEEF );
parse_expected_value( "0xdeadbeef"sv, 0xDEADBEEF );
parse_expected_value( "0xDEADbeef"sv, 0xDEADBEEF );
parse_expected_value( "0xDEAD_BEEF"sv, 0xDEADBEEF );
parse_expected_value( "0xdead_beef"sv, 0xDEADBEEF );
parse_expected_value( "0xdead_BEEF"sv, 0xDEADBEEF );
parse_expected_value( "0xFF"sv, 0xFF );
parse_expected_value( "0x00FF"sv, 0xFF );
parse_expected_value( "0x0000FF"sv, 0xFF );
parse_expected_value( "0o777"sv, 0777 );
parse_expected_value( "0o7_7_7"sv, 0777 );
parse_expected_value( "0o007"sv, 0007 );
parse_expected_value( "0b10000"sv, 0b10000 );
parse_expected_value( "0b010000"sv, 0b10000 );
parse_expected_value( "0b01_00_00"sv, 0b10000 );
parse_expected_value( "0b111111"sv, 0b111111 );
}

View File

@ -0,0 +1,132 @@
#include "tests.h"
TEST_CASE("parsing key-value pairs")
{
parsing_should_succeed(S(R"(
key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 4);
CHECK(tbl[S("key")] == S("value"sv));
CHECK(tbl[S("bare_key")] == S("value"sv));
CHECK(tbl[S("bare-key")] == S("value"sv));
CHECK(tbl[S("1234")] == S("value"sv));
}
);
parsing_should_fail(S(R"(key = # INVALID)"sv));
parsing_should_succeed(S(R"(
"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("127.0.0.1")] == S("value"sv));
CHECK(tbl[S("character encoding")] == S("value"sv));
CHECK(tbl[S("ʎǝʞ")] == S("value"sv));
CHECK(tbl[S("key2")] == S("value"sv));
CHECK(tbl[S("quoted \"value\"")] == S("value"sv));
}
);
parsing_should_fail(S(R"(= "no key name")"sv));
parsing_should_fail(S(R"(
# DO NOT DO THIS
name = "Tom"
name = "Pradyun"
)"sv)
);
}
TEST_CASE("parsing key-value pairs - dotted")
{
parsing_should_succeed(S(R"(
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 3);
CHECK(tbl[S("name")] == S("Orange"sv));
CHECK(tbl[S("physical")][S("color")] == S("orange"sv));
CHECK(tbl[S("physical")][S("shape")] == S("round"sv));
CHECK(tbl[S("site")][S("google.com")] == true);
}
);
parsing_should_succeed(S(R"(
fruit.apple.smooth = true
fruit.orange = 2
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("fruit")][S("apple")][S("smooth")] == true);
CHECK(tbl[S("fruit")][S("orange")] == 2);
}
);
parsing_should_fail(S(R"(
# THIS IS INVALID
fruit.apple = 1
fruit.apple.smooth = true
)"sv)
);
parsing_should_succeed(S(R"(
# VALID BUT DISCOURAGED
apple.type = "fruit"
orange.type = "fruit"
apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange"
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("apple")][S("type")] == S("fruit"sv));
CHECK(tbl[S("apple")][S("skin")] == S("thin"sv));
CHECK(tbl[S("apple")][S("color")] == S("red"sv));
CHECK(tbl[S("orange")][S("type")] == S("fruit"sv));
CHECK(tbl[S("orange")][S("skin")] == S("thick"sv));
CHECK(tbl[S("orange")][S("color")] == S("orange"sv));
}
);
parsing_should_succeed(S(R"(
# RECOMMENDED
apple.type = "fruit"
apple.skin = "thin"
apple.color = "red"
orange.type = "fruit"
orange.skin = "thick"
orange.color = "orange"
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("apple")][S("type")] == S("fruit"sv));
CHECK(tbl[S("apple")][S("skin")] == S("thin"sv));
CHECK(tbl[S("apple")][S("color")] == S("red"sv));
CHECK(tbl[S("orange")][S("type")] == S("fruit"sv));
CHECK(tbl[S("orange")][S("skin")] == S("thick"sv));
CHECK(tbl[S("orange")][S("color")] == S("orange"sv));
}
);
}

View File

@ -0,0 +1,88 @@
#include "tests.h"
TOML_PUSH_WARNINGS
TOML_DISABLE_FIELD_INIT_WARNING
TEST_CASE("parsing TOML spec example")
{
static constexpr auto toml_text =
S(R"(# This is a TOML document.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ]
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
])"sv);
parsing_should_succeed(toml_text, [](table&& tbl) noexcept
{
CHECK(tbl.size() == 5);
CHECK(tbl[S("title")] == S("TOML Example"sv));
CHECK(tbl[S("owner")]);
CHECK(tbl[S("owner")].as<table>());
CHECK(tbl[S("owner")][S("name")] == S("Tom Preston-Werner"sv));
const auto dob = date_time{ { 1979, 5, 27 }, { 7, 32 }, time_offset{ -8 } };
CHECK(tbl[S("owner")][S("dob")] == dob);
CHECK(tbl[S("database")].as<table>());
CHECK(tbl[S("database")][S("server")] == S("192.168.1.1"sv));
const auto ports = { 8001, 8001, 8002 };
CHECK(tbl[S("database")][S("ports")] == ports);
CHECK(tbl[S("database")][S("connection_max")] == 5000);
CHECK(tbl[S("database")][S("enabled")] == true);
CHECK(tbl[S("servers")].as<table>());
CHECK(tbl[S("servers")][S("alpha")].as<table>());
CHECK(tbl[S("servers")][S("alpha")][S("ip")] == S("10.0.0.1"sv));
CHECK(tbl[S("servers")][S("alpha")][S("dc")] == S("eqdc10"sv));
CHECK(tbl[S("servers")][S("beta")].as<table>());
CHECK(tbl[S("servers")][S("beta")][S("ip")] == S("10.0.0.2"sv));
CHECK(tbl[S("servers")][S("beta")][S("dc")] == S("eqdc10"sv));
CHECK(tbl[S("clients")].as<table>());
REQUIRE(tbl[S("clients")][S("data")].as<array>());
CHECK(tbl[S("clients")][S("data")].as<array>()->size() == 2);
REQUIRE(tbl[S("clients")][S("data")][0].as<array>());
CHECK(tbl[S("clients")][S("data")][0].as<array>()->size() == 2);
CHECK(tbl[S("clients")][S("data")][0][0] == S("gamma"sv));
CHECK(tbl[S("clients")][S("data")][0][1] == S("delta"sv));
REQUIRE(tbl[S("clients")][S("data")][1].as<array>());
CHECK(tbl[S("clients")][S("data")][1].as<array>()->size() == 2);
CHECK(tbl[S("clients")][S("data")][1][0] == 1);
CHECK(tbl[S("clients")][S("data")][1][1] == 2);
REQUIRE(tbl[S("clients")][S("hosts")].as<array>());
CHECK(tbl[S("clients")][S("hosts")].as<array>()->size() == 2);
CHECK(tbl[S("clients")][S("hosts")][0] == S("alpha"sv));
CHECK(tbl[S("clients")][S("hosts")][1] == S("omega"sv));
});
}
TOML_POP_WARNINGS

120
tests/parsing_strings.cpp Normal file
View File

@ -0,0 +1,120 @@
#include "tests.h"
TEST_CASE("parsing strings")
{
parsing_should_succeed(S(R"(
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
str1 = """
Roses are red
Violets are blue"""
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("str")] == S("I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."sv));
CHECK(tbl[S("str1")] == S("Roses are red\nViolets are blue"sv));
}
);
parsing_should_succeed(S(R"(
# The following strings are byte-for-byte equivalent:
str1 = "The quick brown fox jumps over the lazy dog."
str2 = """
The quick brown \
fox jumps over \
the lazy dog."""
str3 = """\
The quick brown \
fox jumps over \
the lazy dog.\
"""
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: ""\"""\"""\"""\"""\"."""
# "This," she said, "is just a pointless statement."
str7 = """"This," she said, "is just a pointless statement.""""
)"sv),
[](table&& tbl) noexcept
{
static constexpr auto quick_brown_fox = S("The quick brown fox jumps over the lazy dog."sv);
CHECK(tbl[S("str1")] == quick_brown_fox);
CHECK(tbl[S("str2")] == quick_brown_fox);
CHECK(tbl[S("str3")] == quick_brown_fox);
CHECK(tbl[S("str4")] == S(R"(Here are two quotation marks: "". Simple enough.)"sv));
CHECK(tbl[S("str5")] == S(R"(Here are three quotation marks: """.)"sv));
CHECK(tbl[S("str6")] == S(R"(Here are fifteen quotation marks: """"""""""""""".)"sv));
CHECK(tbl[S("str7")] == S(R"("This," she said, "is just a pointless statement.")"sv));
}
);
parsing_should_fail(S(R"(str5 = """Here are three quotation marks: """.""")"sv));
parsing_should_succeed(S(R"(
# What you see is what you get.
winpath = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>'
regex2 = '''I [dw]on't need \d{2} apples'''
lines = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
'''
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("winpath")] == S(R"(C:\Users\nodejs\templates)"sv));
CHECK(tbl[S("winpath2")] == S(R"(\\ServerX\admin$\system32\)"sv));
CHECK(tbl[S("quoted")] == S(R"(Tom "Dubs" Preston-Werner)"sv));
CHECK(tbl[S("regex")] == S(R"(<\i\c*\s*>)"sv));
CHECK(tbl[S("regex2")] == S(R"(I [dw]on't need \d{2} apples)"sv));
CHECK(tbl[S("lines")] == S(R"(The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
)"sv));
}
);
parsing_should_succeed(S(R"(
quot15 = '''Here are fifteen quotation marks: """""""""""""""'''
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
apos15 = "Here are fifteen apostrophes: '''''''''''''''"
# 'That's still pointless', she said.
str = ''''That's still pointless', she said.'''
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl[S("quot15")] == S(R"(Here are fifteen quotation marks: """"""""""""""")"sv));
CHECK(tbl[S("apos15")] == S(R"(Here are fifteen apostrophes: ''''''''''''''')"sv));
CHECK(tbl[S("str")] == S(R"('That's still pointless', she said.)"sv));
}
);
parsing_should_fail(S(R"(apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID)"sv));
//value tests
parse_expected_value(
R"("The quick brown fox jumps over the lazy dog")"sv,
S("The quick brown fox jumps over the lazy dog"sv));
parse_expected_value(
R"('The quick brown fox jumps over the lazy dog')"sv,
S("The quick brown fox jumps over the lazy dog"sv));
parse_expected_value(
R"("""The quick brown fox jumps over the lazy dog""")"sv,
S("The quick brown fox jumps over the lazy dog"sv));
parse_expected_value(
R"('''The quick brown fox jumps over the lazy dog''')"sv,
S("The quick brown fox jumps over the lazy dog"sv));
}

420
tests/parsing_tables.cpp Normal file
View File

@ -0,0 +1,420 @@
#include "tests.h"
TEST_CASE("parsing tables")
{
parsing_should_succeed(S(R"(
[table]
[table-1]
key1 = "some string"
key2 = 123
[table-2]
key1 = "another string"
key2 = 456
[dog."tater.man"]
type.name = "pug"
[a.b.c] # this is best practice
[ d.e.f ] # same as [d.e.f]
[ g . h . i ] # same as [g.h.i]
[ j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
# [x] you
# [x.y] don't
# [x.y.z] need these
[x.y.z.w] # for this to work
[x] # defining a super-table afterwards is ok
[fruit]
apple.color = "red"
apple.taste.sweet = true
[fruit.apple.texture] # you can add sub-tables
smooth = true
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("table")].as<table>());
CHECK(tbl[S("table")].as<table>()->size() == 0_sz);
REQUIRE(tbl[S("table-1")].as<table>());
CHECK(tbl[S("table-1")].as<table>()->size() == 2_sz);
CHECK(tbl[S("table-1")][S("key1")] == S("some string"sv));
CHECK(tbl[S("table-1")][S("key2")] == 123);
REQUIRE(tbl[S("table-2")].as<table>());
CHECK(tbl[S("table-2")].as<table>()->size() == 2_sz);
CHECK(tbl[S("table-2")][S("key1")] == S("another string"sv));
CHECK(tbl[S("table-2")][S("key2")] == 456);
REQUIRE(tbl[S("dog")].as<table>());
CHECK(tbl[S("dog")].as<table>()->size() == 1_sz);
REQUIRE(tbl[S("dog")][S("tater.man")].as<table>());
CHECK(tbl[S("dog")][S("tater.man")].as<table>()->size() == 1_sz);
CHECK(tbl[S("dog")][S("tater.man")][S("type")][S("name")] == S("pug"sv));
CHECK(tbl[S("a")].as<table>());
CHECK(tbl[S("a")][S("b")].as<table>());
CHECK(tbl[S("a")][S("b")][S("c")].as<table>());
CHECK(tbl[S("d")].as<table>());
CHECK(tbl[S("d")][S("e")].as<table>());
CHECK(tbl[S("d")][S("e")][S("f")].as<table>());
CHECK(tbl[S("g")].as<table>());
CHECK(tbl[S("g")][S("h")].as<table>());
CHECK(tbl[S("g")][S("h")][S("i")].as<table>());
CHECK(tbl[S("j")].as<table>());
CHECK(tbl[S("j")][S("ʞ")].as<table>());
CHECK(tbl[S("j")][S("ʞ")][S("l")].as<table>());
REQUIRE(tbl[S("fruit")].as<table>());
CHECK(tbl[S("fruit")][S("apple")][S("color")] == S("red"sv));
CHECK(tbl[S("fruit")][S("apple")][S("taste")][S("sweet")] == true);
CHECK(tbl[S("fruit")][S("apple")][S("texture")][S("smooth")] == true);
}
);
parsing_should_fail(S(R"(
# DO NOT DO THIS
[fruit]
apple = "red"
[fruit]
orange = "orange"
)"sv));
parsing_should_fail(S(R"(
# DO NOT DO THIS EITHER
[fruit]
apple = "red"
[fruit.apple]
texture = "smooth"
)"sv));
parsing_should_fail(S(R"(
[fruit]
apple.color = "red"
apple.taste.sweet = true
[fruit.apple]
)"sv));
parsing_should_fail(S(R"(
[fruit]
apple.color = "red"
apple.taste.sweet = true
[fruit.apple.taste]
)"sv));
parsing_should_succeed(S(R"(
# VALID BUT DISCOURAGED
[fruit.apple]
[animal]
[fruit.orange]
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("animal")].as<table>());
CHECK(tbl[S("animal")].as<table>()->size() == 0_sz);
REQUIRE(tbl[S("fruit")].as<table>());
CHECK(tbl[S("fruit")].as<table>()->size() == 2_sz);
REQUIRE(tbl[S("fruit")][S("apple")].as<table>());
REQUIRE(tbl[S("fruit")][S("orange")].as<table>());
}
);
parsing_should_succeed(S(R"(
# RECOMMENDED
[fruit.apple]
[fruit.orange]
[animal]
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("animal")].as<table>());
CHECK(tbl[S("animal")].as<table>()->size() == 0_sz);
REQUIRE(tbl[S("fruit")].as<table>());
CHECK(tbl[S("fruit")].as<table>()->size() == 2_sz);
REQUIRE(tbl[S("fruit")][S("apple")].as<table>());
REQUIRE(tbl[S("fruit")][S("orange")].as<table>());
}
);
}
TEST_CASE("parsing inline tables")
{
parsing_should_succeed(S(R"(
name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }
[product]
type = { name = "Nail" }
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("name")].as<table>());
CHECK(tbl[S("name")].as<table>()->size() == 2_sz);
CHECK(tbl[S("name")][S("first")] == S("Tom"sv));
CHECK(tbl[S("name")][S("last")] == S("Preston-Werner"sv));
REQUIRE(tbl[S("point")].as<table>());
CHECK(tbl[S("point")].as<table>()->size() == 2_sz);
CHECK(tbl[S("point")][S("x")] == 1);
CHECK(tbl[S("point")][S("y")] == 2);
REQUIRE(tbl[S("animal")].as<table>());
CHECK(tbl[S("animal")].as<table>()->size() == 1_sz);
REQUIRE(tbl[S("animal")][S("type")].as<table>());
CHECK(tbl[S("animal")][S("type")].as<table>()->size() == 1_sz);
CHECK(tbl[S("animal")][S("type")][S("name")] == S("pug"sv));
REQUIRE(tbl[S("product")].as<table>());
CHECK(tbl[S("product")].as<table>()->size() == 1_sz);
REQUIRE(tbl[S("product")][S("type")].as<table>());
CHECK(tbl[S("product")][S("type")].as<table>()->size() == 1_sz);
CHECK(tbl[S("product")][S("type")][S("name")] == S("Nail"sv));
}
);
parsing_should_fail(S(R"(
[product]
type = { name = "Nail" }
type.edible = false # INVALID
)"sv));
parsing_should_fail(S(R"(
[product]
type.name = "Nail"
type = { edible = false } # INVALID
)"sv));
// "newlines are allowed between the curly braces [if] they are valid within a value."
parsing_should_succeed(S(R"(
test = { val1 = "foo", val2 = [
1, 2,
3
], val3 = "bar" }
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("test")].as<table>());
CHECK(tbl[S("test")].as<table>()->size() == 3_sz);
CHECK(tbl[S("test")][S("val1")] == S("foo"sv));
REQUIRE(tbl[S("test")][S("val2")].as<array>());
CHECK(tbl[S("test")][S("val2")].as<array>()->size() == 3_sz);
CHECK(tbl[S("test")][S("val2")][0] == 1);
CHECK(tbl[S("test")][S("val2")][1] == 2);
CHECK(tbl[S("test")][S("val2")][2] == 3);
CHECK(tbl[S("test")][S("val3")] == S("bar"sv));
}
);
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
{
// toml/issues/516 - allow newlines and trailing commas in inline tables
parsing_should_succeed(S(R"(
name = {
first = "Tom",
last = "Preston-Werner",
}
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("name")].as<table>());
CHECK(tbl[S("name")].as<table>()->size() == 2_sz);
CHECK(tbl[S("name")][S("first")] == S("Tom"sv));
CHECK(tbl[S("name")][S("last")] == S("Preston-Werner"sv));
}
);
}
#else
{
// "A terminating comma (also called trailing comma) is not permitted after the last key/value pair in an inline table."
parsing_should_fail(S(R"(name = { first = "Tom", last = "Preston-Werner", })"sv));
// "No newlines are allowed between the curly braces unless they are valid within a value."
parsing_should_fail(S(R"(
name = {
first = "Tom",
last = "Preston-Werner"
}
)"sv));
}
#endif
}
TEST_CASE("parsing arrays-of-tables")
{
parsing_should_succeed(S(R"(
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
[[products]]
name = "Nail"
sku = 284758393
color = "gray"
[[fruit]]
name = "apple"
[fruit.physical] # subtable
color = "red"
shape = "round"
[[fruit.variety]] # nested array of tables
name = "red delicious"
[[fruit.variety]]
name = "granny smith"
[[fruit]]
name = "banana"
[[fruit.variety]]
name = "plantain"
)"sv),
[](table&& tbl) noexcept
{
REQUIRE(tbl[S("points")].as<array>());
CHECK(tbl[S("points")].as<array>()->size() == 3_sz);
CHECK(tbl[S("points")].as<array>()->is_homogeneous());
CHECK(tbl[S("points")].as<array>()->is_array_of_tables());
CHECK(tbl[S("points")][0][S("x")] == 1);
CHECK(tbl[S("points")][0][S("y")] == 2);
CHECK(tbl[S("points")][0][S("z")] == 3);
CHECK(tbl[S("points")][1][S("x")] == 7);
CHECK(tbl[S("points")][1][S("y")] == 8);
CHECK(tbl[S("points")][1][S("z")] == 9);
CHECK(tbl[S("points")][2][S("x")] == 2);
CHECK(tbl[S("points")][2][S("y")] == 4);
CHECK(tbl[S("points")][2][S("z")] == 8);
REQUIRE(tbl[S("products")].as<array>());
CHECK(tbl[S("products")].as<array>()->size() == 3_sz);
CHECK(tbl[S("products")].as<array>()->is_homogeneous());
CHECK(tbl[S("products")].as<array>()->is_array_of_tables());
REQUIRE(tbl[S("products")][0].as<table>());
CHECK(tbl[S("products")][0].as<table>()->size() == 2_sz);
CHECK(tbl[S("products")][0][S("name")] == S("Hammer"sv));
CHECK(tbl[S("products")][0][S("sku")] == 738594937);
REQUIRE(tbl[S("products")][1].as<table>());
CHECK(tbl[S("products")][1].as<table>()->size() == 0_sz);
REQUIRE(tbl[S("products")][2].as<table>());
CHECK(tbl[S("products")][2].as<table>()->size() == 3_sz);
CHECK(tbl[S("products")][2][S("name")] == S("Nail"sv));
CHECK(tbl[S("products")][2][S("sku")] == 284758393);
CHECK(tbl[S("products")][2][S("color")] == S("gray"sv));
REQUIRE(tbl[S("fruit")].as<array>());
CHECK(tbl[S("fruit")].as<array>()->size() == 2_sz);
CHECK(tbl[S("fruit")].as<array>()->is_homogeneous());
CHECK(tbl[S("fruit")].as<array>()->is_array_of_tables());
REQUIRE(tbl[S("fruit")][0].as<table>());
CHECK(tbl[S("fruit")][0].as<table>()->size() == 3_sz);
CHECK(tbl[S("fruit")][0][S("name")] == S("apple"sv));
REQUIRE(tbl[S("fruit")][0][S("physical")].as<table>());
CHECK(tbl[S("fruit")][0][S("physical")].as<table>()->size() == 2_sz);
CHECK(tbl[S("fruit")][0][S("physical")][S("color")] == S("red"sv));
CHECK(tbl[S("fruit")][0][S("physical")][S("shape")] == S("round"sv));
REQUIRE(tbl[S("fruit")][0][S("variety")].as<array>());
CHECK(tbl[S("fruit")][0][S("variety")].as<array>()->size() == 2_sz);
CHECK(tbl[S("fruit")][0][S("variety")].as<array>()->is_homogeneous());
CHECK(tbl[S("fruit")][0][S("variety")].as<array>()->is_array_of_tables());
CHECK(tbl[S("fruit")][0][S("variety")][0][S("name")] == S("red delicious"sv));
CHECK(tbl[S("fruit")][0][S("variety")][1][S("name")] == S("granny smith"sv));
REQUIRE(tbl[S("fruit")][1].as<table>());
CHECK(tbl[S("fruit")][1].as<table>()->size() == 2_sz);
CHECK(tbl[S("fruit")][1][S("name")] == S("banana"sv));
REQUIRE(tbl[S("fruit")][1][S("variety")].as<array>());
CHECK(tbl[S("fruit")][1][S("variety")].as<array>()->size() == 1_sz);
CHECK(tbl[S("fruit")][1][S("variety")].as<array>()->is_homogeneous());
CHECK(tbl[S("fruit")][1][S("variety")].as<array>()->is_array_of_tables());
CHECK(tbl[S("fruit")][1][S("variety")][0][S("name")] == S("plantain"sv));
}
);
parsing_should_fail(S(R"(
# INVALID TOML DOC
[fruit.physical] # subtable, but to which parent element should it belong?
color = "red"
shape = "round"
[[fruit]] # parser must throw an error upon discovering that "fruit" is
# an array rather than a table
name = "apple"
)"sv));
parsing_should_fail(S(R"(
# INVALID TOML DOC
fruit = []
[[fruit]] # Not allowed
)"sv));
parsing_should_fail(S(R"(
# INVALID TOML DOC
[[fruit]]
name = "apple"
[[fruit.variety]]
name = "red delicious"
# INVALID: This table conflicts with the previous array of tables
[fruit.variety]
name = "granny smith"
)"sv));
parsing_should_fail(S(R"(
# INVALID TOML DOC
[[fruit]]
name = "apple"
[fruit.physical]
color = "red"
shape = "round"
# INVALID: This array of tables conflicts with the previous table
[[fruit.physical]]
color = "green"
)"sv));
}

3
tests/tests.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "tests.h"
// this file is a no-op. it's only here for PCH on MSVC.

187
tests/tests.h Normal file
View File

@ -0,0 +1,187 @@
#pragma once
#define TOML_UNDEF_MACROS 0
#include "../include/toml++/toml.h"
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
#include "catch2.h"
#include <sstream>
using namespace toml;
using namespace Catch::literals;
TOML_POP_WARNINGS
#define S(str) TOML_STRING_PREFIX(str)
template <typename CHAR, typename FUNC>
void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func, std::string_view source_path = {}) noexcept
{
constexpr auto validate_table = [](table&& tabl, std::string_view path) noexcept -> table&&
{
CHECK(tabl.region().begin != source_position{});
CHECK(tabl.region().end != source_position{});
if (path.empty())
CHECK(tabl.region().path == nullptr);
else
{
REQUIRE(tabl.region().path != nullptr);
CHECK(*tabl.region().path == path);
}
return std::move(tabl);
};
#if TOML_EXCEPTIONS
try
{
std::forward<FUNC>(func)(validate_table(toml::parse(toml_str, source_path), source_path));
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
std::forward<FUNC>(func)(validate_table(toml::parse(ss, source_path), source_path));
}
}
catch (const toml::parse_error& err)
{
FAIL(
"Parse error on line "sv << err.where().begin.line
<< ", column "sv << err.where().begin.column
<< ":\n"sv << err.what()
);
}
#else
{
toml::parse_result result = toml::parse(toml_str, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(*std::move(result.root), source_path));
else
{
FAIL(
"Parse error on line "sv << result.error.where.begin.line
<< ", column "sv << result.error.where.begin.column
<< ":\n"sv << result.error.what
);
return;
}
}
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
toml::parse_result result = toml::parse(ss, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(*std::move(result.root), source_path));
else
{
FAIL(
"Parse error on line "sv << result.error.where.begin.line
<< ", column "sv << result.error.where.begin.column
<< ":\n"sv << result.error.what
);
return;
}
}
#endif
}
template <typename CHAR>
void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
{
#if TOML_EXCEPTIONS
static constexpr auto run_tests = [](auto&& fn) noexcept
{
try
{
fn();
}
catch (const toml::parse_error&)
{
SUCCEED("toml::parse_error thrown OK"sv);
return true;
}
catch (const std::exception& exc)
{
FAIL("Expected parsing failure, saw exception: "sv << exc.what());
}
catch (...)
{
FAIL("Expected parsing failure, saw unspecified error"sv);
}
return false;
};
if (run_tests([=]() { (void)toml::parse(toml_str); }))
run_tests([=]()
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
(void)toml::parse(ss);
});
#else
static constexpr auto run_tests = [](auto&& fn) noexcept
{
toml::parse_result result = fn();
if (result)
{
FAIL("Expected parsing failure"sv);
return false;
}
else
{
SUCCEED("toml::parse_error returned OK"sv);
return true;
}
};
if (run_tests([=]() noexcept { return toml::parse(toml_str); }))
run_tests([=]() noexcept
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), toml_str.length());
return toml::parse(ss);
});
#endif
}
template <typename T>
void parse_expected_value(std::string_view value_str, const T& expected) noexcept
{
std::string value;
value.reserve(value_str.length() + 6_sz);
value.append("val = "sv);
value.append(value_str);
static constexpr auto is_val = [](char c) noexcept
{
if constexpr (std::is_same_v<string, value_of<T>>)
return c == '"' || c == '\'';
else
return c != ' ' && c != '\t';
};
size_t begin = 5_sz;
for (; begin < value.length(); begin++)
if (is_val(value[begin]))
break;
begin++;
size_t end = value.length();
for (; end --> 0_sz; )
if (is_val(value[end]))
break;
end += 2_sz;
parsing_should_succeed(std::string_view{ value }, [&](table&& tbl) noexcept
{
CHECK(tbl.size() == 1);
REQUIRE(tbl[S("val"sv)].as<value_of<T>>());
CHECK(tbl[S("val"sv)].as<value_of<T>>()->get() == expected);
CHECK(tbl[S("val"sv)].get()->region().begin == source_position{ 1, static_cast<uint32_t>(begin) });
CHECK(tbl[S("val"sv)].get()->region().end == source_position{ 1, static_cast<uint32_t>(end) });
});
}

6539
toml.hpp Normal file

File diff suppressed because it is too large Load Diff

21
vs/.runsettings Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<!-- Configurations that affect the Test Framework -->
<RunConfiguration>
<MaxCpuCount>1</MaxCpuCount>
<ResultsDirectory>..\build\TestResults</ResultsDirectory><!-- Path relative to solution directory -->
<TestSessionTimeout>60000</TestSessionTimeout><!-- Milliseconds -->
</RunConfiguration>
<!-- Adapter Specific sections -->
<Catch2Adapter>
<DebugBreak>on</DebugBreak><!-- Introduced in v1.1.0 -->
<DiscoverCommandLine>--verbosity high --list-test-names-only</DiscoverCommandLine>
<DiscoverTimeout>500</DiscoverTimeout><!-- Milliseconds -->
<FilenameFilter>(?i:test)</FilenameFilter>
<Logging>debug</Logging>
<WorkingDirectoryRoot>Solution</WorkingDirectoryRoot>
<WorkingDirectory>..\tests\</WorkingDirectory>
</Catch2Adapter>
</RunSettings>

71
vs/example.vcxproj Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{259FCEE5-3442-4076-9547-2BA793ECA1CB}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<PropertyGroup>
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\examples\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\examples\example.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\examples\example.toml" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

96
vs/test_char.vcxproj Normal file
View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{54532B93-A2F9-49AC-886E-767A6D78E2F2}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

96
vs/test_char8.vcxproj Normal file
View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{3E4018CE-CCA2-48E6-B11E-732A1B59C672}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{F094F967-42B5-4AD7-AB44-EA044CD9837E}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{E888E99C-734D-44C4-B917-0AC8D3E2F48F}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{89FF67C6-94C0-4C46-8411-7549A36584FB}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{EAC419E9-0C72-4625-B2B9-E879F697021A}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{F05F8C1B-7E23-4147-901E-AD91092E5752}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

53
vs/toml++.natvis Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="::toml::date">
<DisplayString>{(int)year}-{(int)month}-{(int)day}</DisplayString>
<Expand>
<Item Name="year" ExcludeView="simple">year</Item>
<Item Name="month" ExcludeView="simple">month</Item>
<Item Name="day" ExcludeView="simple">day</Item>
</Expand>
</Type>
<Type Name="::toml::time">
<DisplayString>{(int)hour}:{(int)minute}:{second + (nanosecond / 1000000000.0)}</DisplayString>
<Expand>
<Item Name="hour" ExcludeView="simple">hour</Item>
<Item Name="minute" ExcludeView="simple">minute</Item>
<Item Name="second" ExcludeView="simple">second</Item>
<Item Name="nanosecond" ExcludeView="simple">nanosecond</Item>
</Expand>
</Type>
<Type Name="::toml::time_offset">
<DisplayString Condition="hours &gt;= 0 &amp;&amp; minutes &gt;= 0">{(int)hours}:{(int)minutes}</DisplayString>
<DisplayString Condition="hours &lt; 0 &amp;&amp; minutes &gt;= 0">-{-((int)hours)}:{(int)minutes}</DisplayString>
<DisplayString Condition="hours &lt; 0 &amp;&amp; minutes &lt; 0">-{-((int)hours)}:{-((int)minutes)}</DisplayString>
<DisplayString Condition="hours &gt;= 0 &amp;&amp; minutes &lt; 0">-{(int)hours}:{-((int)minutes)}</DisplayString>
<Expand>
<Item Name="hours" ExcludeView="simple">hours</Item>
<Item Name="minutes" ExcludeView="simple">minutes</Item>
</Expand>
</Type>
<Type Name="::toml::value&lt;*&gt;">
<DisplayString>{{ {val_} }}</DisplayString>
<Expand>
<Item Name="val_" ExcludeView="simple">val_</Item>
</Expand>
</Type>
<Type Name="::toml::source_position">
<DisplayString>line {line}, column {column}</DisplayString>
<Expand>
<Item Name="line" ExcludeView="simple">line</Item>
<Item Name="column" ExcludeView="simple">column</Item>
</Expand>
</Type>
<Type Name="::toml::impl::utf8_codepoint">
<DisplayString>{&amp;bytes,s8} ({position})</DisplayString>
</Type>
</AutoVisualizer>

105
vs/toml++.props Normal file
View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildInfoJobStartTicks>$([System.DateTime]::Now.Ticks)</BuildInfoJobStartTicks>
</PropertyGroup>
<!-- :: defaults -->
<PropertyGroup>
<OutDir>$(SolutionDir)..\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)..\build\$(TargetName)$(TargetExt)-$(PlatformTarget)-$(Configuration)-$(PlatformToolsetVersion)\</IntDir>
<IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<ControlFlowGuard>false</ControlFlowGuard>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <!-- /GR- -->
<FloatingPointExceptions>false</FloatingPointExceptions> <!-- /fp:except- -->
<ExceptionHandling>Sync</ExceptionHandling> <!-- /EHsc -->
<ConformanceMode>true</ConformanceMode> <!-- /permissive- -->
<StringPooling>true</StringPooling> <!-- /GF -->
<OpenMPSupport>false</OpenMPSupport> <!-- /openmp- -->
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <!-- /Zi -->
<IntrinsicFunctions>true</IntrinsicFunctions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<TreatWarningAsError>true</TreatWarningAsError>
<WarningLevel>Level4</WarningLevel>
<LanguageStandard>stdcpplatest</LanguageStandard>
<DiagnosticsFormat>Caret</DiagnosticsFormat>
<AdditionalOptions>%(AdditionalOptions) /utf-8 /volatile:iso /Zc:__cplusplus /bigobj /Zc:inline /Zc:throwingNew</AdditionalOptions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_CONSOLE</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_ITERATOR_DEBUG_LEVEL=0</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_ITERATOR_DEBUG_LEVEL=0</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WINSOCK_DEPRECATED_NO_WARNINGS</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_SCL_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_MSC_TOOLSET_VER=$(PlatformToolsetVersion)</PreprocessorDefinitions>
</ClCompile>
<Link>
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<!-- :: debug -->
<PropertyGroup Condition="$(Configuration.ToLower().Contains('debug'))">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="$(Configuration.ToLower().Contains('debug'))">
<ClCompile>
<Optimization>Disabled</Optimization> <!-- /Od -->
<OmitFramePointers>false</OmitFramePointers> <!-- /Oy- -->
<PreprocessorDefinitions>%(PreprocessorDefinitions);_DEBUG</PreprocessorDefinitions>
</ClCompile>
<Link>
<OptimizeReferences>false</OptimizeReferences> <!-- /OPT:NOREF -->
<EnableCOMDATFolding>false</EnableCOMDATFolding> <!-- /OPT:NOICF -->
</Link>
</ItemDefinitionGroup>
<!-- :: release -->
<ItemDefinitionGroup Condition="!$(Configuration.ToLower().Contains('debug'))">
<ClCompile>
<Optimization>MaxSpeed</Optimization> <!-- /O2 -->
<OmitFramePointers>true</OmitFramePointers> <!-- /Oy -->
<PreprocessorDefinitions>%(PreprocessorDefinitions);NDEBUG</PreprocessorDefinitions>
<InlineFunctionExpansion Condition="$(PlatformToolsetVersion) &lt;= 141">AnySuitable</InlineFunctionExpansion> <!-- /Ob2 -->
<AdditionalOptions Condition="$(PlatformToolsetVersion) &gt;= 142">%(AdditionalOptions) /Ob3</AdditionalOptions> <!-- /Ob3 -->
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<!-- :: 32-bit -->
<ItemDefinitionGroup Condition="'$(PlatformArchitecture)'=='32'">
<ClCompile>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> <!-- /arch:SSE2 -->
</ClCompile>
</ItemDefinitionGroup>
<!-- :: 64-bit -->
<ItemDefinitionGroup Condition="'$(PlatformArchitecture)'=='64'">
<ClCompile>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions</EnableEnhancedInstructionSet> <!-- /arch:AVX -->
</ClCompile>
</ItemDefinitionGroup>
<!-- Report how long each build took -->
<Target Name="BuildInfoReportDuration" AfterTargets="Build">
<Message
Importance="high"
Text="===== $(ProjectName) ($(Configuration) $(Platform)) built in $([System.TimeSpan]::FromTicks($([System.DateTime]::Now.Ticks))
.Subtract($([System.TimeSpan]::FromTicks($(BuildInfoJobStartTicks))))
.ToString()
). ====="
/>
</Target>
</Project>

133
vs/toml++.sln Normal file
View File

@ -0,0 +1,133 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29519.161
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toml++", "toml++.vcxproj", "{0E287B5A-1168-43FD-B067-F6BE8E182A57}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example.vcxproj", "{259FCEE5-3442-4076-9547-2BA793ECA1CB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_char", "test_char.vcxproj", "{54532B93-A2F9-49AC-886E-767A6D78E2F2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_char_noexcept", "test_char_noexcept.vcxproj", "{E888E99C-734D-44C4-B917-0AC8D3E2F48F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_char8", "test_char8.vcxproj", "{3E4018CE-CCA2-48E6-B11E-732A1B59C672}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_char8_noexcept", "test_char8_noexcept.vcxproj", "{F094F967-42B5-4AD7-AB44-EA044CD9837E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_strict_char", "test_strict_char.vcxproj", "{89FF67C6-94C0-4C46-8411-7549A36584FB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_strict_char_noexcept", "test_strict_char_noexcept.vcxproj", "{F05F8C1B-7E23-4147-901E-AD91092E5752}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_strict_char8", "test_strict_char8.vcxproj", "{EAC419E9-0C72-4625-B2B9-E879F697021A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_strict_char8_noexcept", "test_strict_char8_noexcept.vcxproj", "{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x64.ActiveCfg = Debug|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x64.Build.0 = Debug|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x86.ActiveCfg = Debug|Win32
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x86.Build.0 = Debug|Win32
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x64.ActiveCfg = Release|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x64.Build.0 = Release|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x86.ActiveCfg = Release|Win32
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x86.Build.0 = Release|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x64.ActiveCfg = Debug|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x64.Build.0 = Debug|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x86.ActiveCfg = Debug|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x86.Build.0 = Debug|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x64.ActiveCfg = Release|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x64.Build.0 = Release|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x86.ActiveCfg = Release|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x86.Build.0 = Release|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x64.ActiveCfg = Debug|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x64.Build.0 = Debug|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x86.ActiveCfg = Debug|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x86.Build.0 = Debug|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x64.ActiveCfg = Release|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x64.Build.0 = Release|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x86.ActiveCfg = Release|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x86.Build.0 = Release|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x64.ActiveCfg = Debug|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x64.Build.0 = Debug|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x86.ActiveCfg = Debug|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x86.Build.0 = Debug|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x64.ActiveCfg = Release|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x64.Build.0 = Release|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x86.ActiveCfg = Release|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x86.Build.0 = Release|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x64.ActiveCfg = Debug|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x64.Build.0 = Debug|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x86.ActiveCfg = Debug|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x86.Build.0 = Debug|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x64.ActiveCfg = Release|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x64.Build.0 = Release|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x86.ActiveCfg = Release|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x86.Build.0 = Release|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x64.ActiveCfg = Debug|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x64.Build.0 = Debug|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x86.ActiveCfg = Debug|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x86.Build.0 = Debug|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x64.ActiveCfg = Release|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x64.Build.0 = Release|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x86.ActiveCfg = Release|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x86.Build.0 = Release|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x64.ActiveCfg = Debug|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x64.Build.0 = Debug|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x86.ActiveCfg = Debug|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x86.Build.0 = Debug|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x64.ActiveCfg = Release|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x64.Build.0 = Release|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x86.ActiveCfg = Release|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x86.Build.0 = Release|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x64.ActiveCfg = Debug|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x64.Build.0 = Debug|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x86.ActiveCfg = Debug|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x86.Build.0 = Debug|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x64.ActiveCfg = Release|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x64.Build.0 = Release|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x86.ActiveCfg = Release|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x86.Build.0 = Release|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x64.ActiveCfg = Debug|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x64.Build.0 = Debug|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x86.ActiveCfg = Debug|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x86.Build.0 = Debug|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x64.ActiveCfg = Release|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x64.Build.0 = Release|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x86.ActiveCfg = Release|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x86.Build.0 = Release|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x64.ActiveCfg = Debug|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x64.Build.0 = Debug|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x86.ActiveCfg = Debug|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x86.Build.0 = Debug|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x64.ActiveCfg = Release|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x64.Build.0 = Release|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x86.ActiveCfg = Release|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{54532B93-A2F9-49AC-886E-767A6D78E2F2} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{E888E99C-734D-44C4-B917-0AC8D3E2F48F} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{3E4018CE-CCA2-48E6-B11E-732A1B59C672} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{F094F967-42B5-4AD7-AB44-EA044CD9837E} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{89FF67C6-94C0-4C46-8411-7549A36584FB} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{F05F8C1B-7E23-4147-901E-AD91092E5752} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{EAC419E9-0C72-4625-B2B9-E879F697021A} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0926DDCC-88CD-4839-A82D-D9B99E02A0B1}
EndGlobalSection
EndGlobal

78
vs/toml++.vcxproj Normal file
View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{0E287B5A-1168-43FD-B067-F6BE8E182A57}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="$(ProjectDir)\toml++.props" />
<ItemGroup>
<ClInclude Include="..\include\toml++\toml.h" />
<ClInclude Include="..\include\toml++\toml_array.h" />
<ClInclude Include="..\include\toml++\toml_common.h" />
<ClInclude Include="..\include\toml++\toml_formatter.h" />
<ClInclude Include="..\include\toml++\toml_node.h" />
<ClInclude Include="..\include\toml++\toml_parser.h" />
<ClInclude Include="..\include\toml++\toml_node_view.h" />
<ClInclude Include="..\include\toml++\toml_utf8_generated.h" />
<ClInclude Include="..\include\toml++\toml_table.h" />
<ClInclude Include="..\include\toml++\toml_utf8.h" />
<ClInclude Include="..\include\toml++\toml_value.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" />
<None Include="..\python\generate_single_header.py" />
<None Include="..\python\generate_unicode_functions.py" />
<None Include="..\README.md" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

22
vs/toml++.vcxproj.filters Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="..\include\toml++\toml_array.h" />
<ClInclude Include="..\include\toml++\toml_value.h" />
<ClInclude Include="..\include\toml++\toml_parser.h" />
<ClInclude Include="..\include\toml++\toml_table.h" />
<ClInclude Include="..\include\toml++\toml_common.h" />
<ClInclude Include="..\include\toml++\toml.h" />
<ClInclude Include="..\include\toml++\toml_utf8.h" />
<ClInclude Include="..\include\toml++\toml_node.h" />
<ClInclude Include="..\include\toml++\toml_node_view.h" />
<ClInclude Include="..\include\toml++\toml_utf8_generated.h" />
<ClInclude Include="..\include\toml++\toml_formatter.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" />
<None Include="..\README.md" />
<None Include="..\python\generate_single_header.py" />
<None Include="..\python\generate_unicode_functions.py" />
</ItemGroup>
</Project>