From 930bf0ad5885104b053fe636d9ed562e5dded6af Mon Sep 17 00:00:00 2001 From: Mark Gillard Date: Sat, 4 Jan 2020 16:21:38 +0200 Subject: [PATCH] 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 --- .circleci/config.yml | 45 + .editorconfig | 17 + .gitattributes | 17 + .gitignore | 359 ++ .gitmodules | 3 + LICENSE | 18 + README.md | 142 + examples/example.cpp | 45 + examples/example.toml | 94 + examples/meson.build | 5 + include/toml++/toml.h | 49 + include/toml++/toml_array.h | 83 + include/toml++/toml_common.h | 623 +++ include/toml++/toml_formatter.h | 717 +++ include/toml++/toml_node.h | 132 + include/toml++/toml_node_view.h | 312 ++ include/toml++/toml_parser.h | 2801 +++++++++++ include/toml++/toml_table.h | 82 + include/toml++/toml_utf8.h | 600 +++ include/toml++/toml_utf8_generated.h | 985 ++++ include/toml++/toml_value.h | 113 + meson.build | 28 + python/ci_single_header_check.py | 64 + python/generate_single_header.py | 137 + python/generate_unicode_functions.py | 528 ++ tests/catch2 | 1 + tests/catch2.h | 55 + tests/lifetimes.cpp | 40 + tests/main.cpp | 11 + tests/meson.build | 73 + tests/parsing_arrays.cpp | 140 + tests/parsing_booleans.cpp | 27 + tests/parsing_comments.cpp | 17 + tests/parsing_dates_and_times.cpp | 43 + tests/parsing_floats.cpp | 112 + tests/parsing_integers.cpp | 151 + tests/parsing_key_value_pairs.cpp | 132 + tests/parsing_spec_example.cpp | 88 + tests/parsing_strings.cpp | 120 + tests/parsing_tables.cpp | 420 ++ tests/tests.cpp | 3 + tests/tests.h | 187 + toml.hpp | 6539 +++++++++++++++++++++++++ vs/.runsettings | 21 + vs/example.vcxproj | 71 + vs/test_char.vcxproj | 96 + vs/test_char8.vcxproj | 96 + vs/test_char8_noexcept.vcxproj | 98 + vs/test_char_noexcept.vcxproj | 98 + vs/test_strict_char.vcxproj | 97 + vs/test_strict_char8.vcxproj | 97 + vs/test_strict_char8_noexcept.vcxproj | 99 + vs/test_strict_char_noexcept.vcxproj | 99 + vs/toml++.natvis | 53 + vs/toml++.props | 105 + vs/toml++.sln | 133 + vs/toml++.vcxproj | 78 + vs/toml++.vcxproj.filters | 22 + 58 files changed, 17421 insertions(+) create mode 100644 .circleci/config.yml create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 LICENSE create mode 100644 README.md create mode 100644 examples/example.cpp create mode 100644 examples/example.toml create mode 100644 examples/meson.build create mode 100644 include/toml++/toml.h create mode 100644 include/toml++/toml_array.h create mode 100644 include/toml++/toml_common.h create mode 100644 include/toml++/toml_formatter.h create mode 100644 include/toml++/toml_node.h create mode 100644 include/toml++/toml_node_view.h create mode 100644 include/toml++/toml_parser.h create mode 100644 include/toml++/toml_table.h create mode 100644 include/toml++/toml_utf8.h create mode 100644 include/toml++/toml_utf8_generated.h create mode 100644 include/toml++/toml_value.h create mode 100644 meson.build create mode 100644 python/ci_single_header_check.py create mode 100644 python/generate_single_header.py create mode 100644 python/generate_unicode_functions.py create mode 160000 tests/catch2 create mode 100644 tests/catch2.h create mode 100644 tests/lifetimes.cpp create mode 100644 tests/main.cpp create mode 100644 tests/meson.build create mode 100644 tests/parsing_arrays.cpp create mode 100644 tests/parsing_booleans.cpp create mode 100644 tests/parsing_comments.cpp create mode 100644 tests/parsing_dates_and_times.cpp create mode 100644 tests/parsing_floats.cpp create mode 100644 tests/parsing_integers.cpp create mode 100644 tests/parsing_key_value_pairs.cpp create mode 100644 tests/parsing_spec_example.cpp create mode 100644 tests/parsing_strings.cpp create mode 100644 tests/parsing_tables.cpp create mode 100644 tests/tests.cpp create mode 100644 tests/tests.h create mode 100644 toml.hpp create mode 100644 vs/.runsettings create mode 100644 vs/example.vcxproj create mode 100644 vs/test_char.vcxproj create mode 100644 vs/test_char8.vcxproj create mode 100644 vs/test_char8_noexcept.vcxproj create mode 100644 vs/test_char_noexcept.vcxproj create mode 100644 vs/test_strict_char.vcxproj create mode 100644 vs/test_strict_char8.vcxproj create mode 100644 vs/test_strict_char8_noexcept.vcxproj create mode 100644 vs/test_strict_char_noexcept.vcxproj create mode 100644 vs/toml++.natvis create mode 100644 vs/toml++.props create mode 100644 vs/toml++.sln create mode 100644 vs/toml++.vcxproj create mode 100644 vs/toml++.vcxproj.filters diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..0331dbf --- /dev/null +++ b/.circleci/config.yml @@ -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 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..de79ff5 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..2b8c948 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0ef4d4 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..aeea08c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/catch2"] + path = tests/catch2 + url = https://github.com/catchorg/Catch2.git diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a973a7 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..45cc862 --- /dev/null +++ b/README.md @@ -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) + +
+ +# Usage +`toml++` comes in two flavours: Regular and Single-header. + +### Regular mode +1. Add `tomlplusplus/include` to your include paths +2. `#include ` + +### 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. + +
+ +# 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)`
(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]. | + +
+ +# 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 >>`. + +
+ +# 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 +``` + +
+ +# 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 diff --git a/examples/example.cpp b/examples/example.cpp new file mode 100644 index 0000000..6c5d59c --- /dev/null +++ b/examples/example.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#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; +} diff --git a/examples/example.toml b/examples/example.toml new file mode 100644 index 0000000..b450128 --- /dev/null +++ b/examples/example.toml @@ -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" \ No newline at end of file diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..551a98f --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,5 @@ +example = executable( + 'example', + [ 'example.cpp' ], + include_directories : inc +) diff --git a/include/toml++/toml.h b/include/toml++/toml.h new file mode 100644 index 0000000..3d14214 --- /dev/null +++ b/include/toml++/toml.h @@ -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 diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h new file mode 100644 index 0000000..ece1005 --- /dev/null +++ b/include/toml++/toml_array.h @@ -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> 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 + [[nodiscard]] + node_of* get_as(size_t index) noexcept + { + return get(index)->as(); + } + + template + [[nodiscard]] + const node_of* get_as(size_t index) const noexcept + { + return get(index)->as(); + } + }; +} diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h new file mode 100644 index 0000000..0ff7fe9 --- /dev/null +++ b/include/toml++/toml_common.h @@ -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 +#include //memcpy, memset +#include //log10 +#include +#include +#include +#include +#include +#include +#include +#include +#if TOML_USE_STREAMS_FOR_FLOATS + #include +#endif +#if TOML_EXCEPTIONS + #include +#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(n); + } + + [[nodiscard]] TOML_ALWAYS_INLINE + TOML_CONSTEVAL size_t operator"" _sz(unsigned long long n) noexcept + { + return static_cast(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 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 + using string_map = std::map>; //heterogeneous lookup + + class node; + template + class node_view; + template + class value; + class array; + class table; + + class default_formatter; + + namespace impl + { + #if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20)) + + template + using remove_cvref_t = std::remove_cvref_t; + + #else + + template + using remove_cvref_t = std::remove_cv_t>; + + #endif + + class parser; + + template + inline constexpr bool is_value = + std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + + template + inline constexpr bool is_value_or_promotable = + is_value + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + + template + inline constexpr bool is_value_or_node = + is_value + || std::is_same_v + || std::is_same_v; + + template struct node_wrapper { using type = T; }; + template <> struct node_wrapper { using type = value; }; + template <> struct node_wrapper { using type = value; }; + template <> struct node_wrapper { using type = value; }; + template <> struct node_wrapper { using type = value; }; + template <> struct node_wrapper { using type = value; }; + template <> struct node_wrapper