GithubHelp home page GithubHelp logo

marzer / tomlplusplus Goto Github PK

View Code? Open in Web Editor NEW
1.4K 28.0 141.0 17.33 MB

Header-only TOML config file parser and serializer for C++17.

Home Page: https://marzer.github.io/tomlplusplus/

License: MIT License

C++ 96.32% Python 2.39% Meson 0.94% C 0.01% CMake 0.25% Batchfile 0.08% Shell 0.02%
toml cplusplus-17 cplusplus-20 header-only configuration-files cpp cpp17 cpp20 parser serializer

tomlplusplus's Introduction

banner Releases C++17 TOML MIT license ci Mentioned in Awesome C++ Sponsor Gitter

toml++ homepage

✨️ This README is fine, but the toml++ homepage is better. ✨️


Library features

  • Header-only (optional!)
  • Supports the latest TOML release (v1.0.0), plus optional support for some unreleased TOML features
  • Passes all tests in the toml-test suite
  • Supports serializing to JSON and YAML
  • Proper UTF-8 handling (incl. BOM)
  • C++17 (plus some C++20 features where available, e.g. experimental support for char8_t strings)
  • Doesn't require RTTI
  • Works with or without exceptions
  • Tested on Clang (8+), GCC (8+) and MSVC (VS2019)
  • Tested on x64, x86 and ARM

Basic usage

ℹ️ The following example favours brevity. If you'd prefer full API documentation and lots of specific code snippets instead, visit the project homepage

Given a TOML file configuration.toml containing the following:

[library]
name = "toml++"
authors = ["Mark Gillard <[email protected]>"]

[dependencies]
cpp = 17

Reading it in C++ is easy with toml++:

#include <toml++/toml.hpp>

auto config = toml::parse_file( "configuration.toml" );

// get key-value pairs
std::string_view library_name = config["library"]["name"].value_or(""sv);
std::string_view library_author = config["library"]["authors"][0].value_or(""sv);
int64_t depends_on_cpp_version = config["dependencies"]["cpp"].value_or(0);

// modify the data
config.insert_or_assign("alternatives", toml::array{
    "cpptoml",
    "toml11",
    "Boost.TOML"
});

// use a visitor to iterate over heterogenous data
config.for_each([](auto& key, auto& value)
{
    std::cout << value << "\n";
    if constexpr (toml::is_string<decltype(value)>)
        do_something_with_string_values(value);
});

// you can also iterate more 'traditionally' using a ranged-for
for (auto&& [k, v] : config)
{
    // ...
}

// re-serialize as TOML
std::cout << config << "\n";

// re-serialize as JSON
std::cout << toml::json_formatter{ config } << "\n";

// re-serialize as YAML
std::cout << toml::yaml_formatter{ config } << "\n";

You'll find some more code examples in the examples directory, and plenty more as part of the API documentation.


Adding toml++ to your project

toml++ comes in two flavours: Single-header and Regular. The API is the same for both.

🍦️ Single-header flavour

  1. Drop toml.hpp wherever you like in your source tree
  2. There is no step two

🍨️ Regular flavour

  1. Clone the repository
  2. Add tomlplusplus/include to your include paths
  3. #include <toml++/toml.hpp>

Conan

Add tomlplusplus/3.4.0 to your conanfile.

DDS

Add tomlpp to your package.json5, e.g.:

depends: [
    'tomlpp^3.4.0',
]

ℹ️ What is DDS?

Tipi.build

tomlplusplus can be easily used in tipi.build projects by adding the following entry to your .tipi/deps:

{
	"marzer/tomlplusplus": {}
}

Vcpkg

vcpkg install tomlplusplus

Meson

You can install the wrap with:

meson wrap install tomlplusplus

After that, you can use it like a regular dependency:

tomlplusplus_dep = dependency('tomlplusplus')

You can also add it as a subproject directly.

CMake FetchContent

include(FetchContent)
FetchContent_Declare(
    tomlplusplus
    GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
    GIT_TAG        v3.4.0
)
FetchContent_MakeAvailable(tomlplusplus)
# Example add library: target_link_libraries(MyApp tomlplusplus::tomlplusplus)

ℹ️ What is FetchContent?

Git submodules

git submodule add --depth 1 https://github.com/marzer/tomlplusplus.git tomlplusplus

Other environments and package managers

The C++ tooling ecosystem is a fractal nightmare of unbridled chaos so naturally I'm not up-to-speed with all of the available packaging and integration options. I'm always happy to see new ones supported, though! If there's some integration you'd like to see and have the technical know-how to make it happen, feel free to make a pull request.

What about dependencies?

If you just want to consume toml++ as a regular library then you don't have any dependencies to worry about. There's a few test-related dependencies to be aware of if you're working on the library, though. See CONTRIBUTING for information.


Configuration

A number of configurable options are exposed in the form of preprocessor #defines Most likely you won't need to mess with these at all, but if you do, set them before including toml++.

Option Type Description Default
TOML_ASSERT(expr) function macro Sets the assert function used by the library. assert()
TOML_CALLCONV define Calling convention to apply to exported free/static functions. undefined
TOML_CONFIG_HEADER string literal Includes the given header file before the rest of the library. undefined
TOML_ENABLE_FORMATTERS boolean Enables the formatters. Set to 0 if you don't need them to improve compile times and binary size. 1
TOML_ENABLE_FLOAT16 boolean Enables support for the built-in _Float16 type. per compiler settings
TOML_ENABLE_PARSER boolean Enables the parser. Set to 0 if you don't need it to improve compile times and binary size. 1
TOML_ENABLE_UNRELEASED_FEATURES boolean Enables support for unreleased TOML language features. 0
TOML_ENABLE_WINDOWS_COMPAT boolean Enables support for transparent conversion between wide and narrow strings. 1 on Windows
TOML_EXCEPTIONS boolean Sets whether the library uses exceptions. per compiler settings
TOML_EXPORTED_CLASS define API export annotation to add to classes. undefined
TOML_EXPORTED_MEMBER_FUNCTION define API export annotation to add to non-static class member functions. undefined
TOML_EXPORTED_FREE_FUNCTION define API export annotation to add to free functions. undefined
TOML_EXPORTED_STATIC_FUNCTION define API export annotation to add to static functions. undefined
TOML_HEADER_ONLY boolean Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library). 1
TOML_IMPLEMENTATION define Define this to enable compilation of the library's implementation when TOML_HEADER_ONLY == 0. undefined
TOML_OPTIONAL_TYPE type name Overrides the optional<T> type used by the library if you need something better than std::optional. undefined
TOML_SMALL_FLOAT_TYPE type name If your codebase has a custom 'small float' type (e.g. half-precision), this tells toml++ about it. undefined
TOML_SMALL_INT_TYPE type name If your codebase has a custom 'small integer' type (e.g. 24-bits), this tells toml++ about it. undefined

ℹ️ A number of these have ABI implications; the library uses inline namespaces to prevent you from accidentally linking incompatible combinations together.


TOML Language Support

At any given time the library aims to support whatever the most recently-released version of TOML is, with opt-in support for a number 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_PATCH.

Unreleased language features:

  • #516: Allow newlines and trailing commas in inline tables
  • #562: Allow hex floating-point values
  • #644: Support + in key names
  • #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
  • #790: Include an \e escape code sequence (shorthand for \u001B)
  • #796: Include an \xHH escape code sequence
  • #891: Allow non-English scripts for unquoted keys

ℹ️ #define TOML_ENABLE_UNRELEASED_FEATURES 1 to enable these features (see Configuration).

🔹️ TOML v1.0.0:

All features supported, including:

  • #356: Allow leading zeros in the exponent part of a float
  • #567: Control characters are not permitted in comments
  • #571: Allow raw tabs inside strings
  • #665: Make arrays heterogeneous
  • #766: Allow comments before commas in arrays

🔹️ TOML v0.5.0:

All features supported.


Contributing

Contributions are very welcome! Either by reporting issues or submitting pull requests. If you wish to submit a pull request, please see CONTRIBUTING for all the details you need to get going.


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'.

With thanks to:


Contact

For bug reports and feature requests please consider using the issues system here on GitHub. For anything else though you're welcome to reach out via other means. In order of likely response time:

tomlplusplus's People

Contributors

beastle9end avatar capuanob avatar chronoxor avatar claudeha avatar clausklein avatar cskeeters avatar diizzyy avatar friendlyanon avatar gelldur avatar giulioromualdi avatar hazardyknusperkeks avatar ismagilli avatar jonestristand avatar kcsaul avatar mabi19 avatar marzer avatar prince-chrismc avatar proydakov avatar pysco68 avatar reedbeta avatar rezahousseini avatar rsmmr avatar ryan-rsm-mckenzie avatar shatur avatar shdnx avatar tachi107 avatar tambry avatar unixy2k avatar whiterabbit963 avatar ximion avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tomlplusplus's Issues

Including toml++ as a subproject

Is your feature request related to a problem? Please describe.
The Meson build file doesn't define a dependency variable which makes it (as far as I can tell) difficult to use as a subproject (via wraps) in an existing Meson project.

Describe the solution you'd like
From what I can gather from the documentation and several other libraries (to list a few), probably something like

tomlplusplus_dep = declare_dependency(
  include_directories : inc,
  version : meson.project_version(),
)

added at the end of meson.build. I admit I'm not entirely sure if this is the correct way of solving this, so I think an issue is more appropriate than a PR for now.

Need to include header <fstream> to call toml::parse_file

Environment

Compiler:
GCC 9.1

C++ standard mode (e.g. 17, 20, 'latest'):
C++20

Target arch (e.g. x64):
x64

Exceptions enabled:
Default

Relevant toml++ configuration customizations:
Use header-only <toml.hpp>

Relevant compilation flags:
-std=gnu++2a -Wall -Wextra -Wno-unused-parameter -O3 -march=native

Describe the bug

Follow the readme to parse a toml file:

#include "toml.hpp"
auto config = toml::parse_file("config.toml");

which reports:

src/toml.hpp:5028:8: error: too many initializers for ‘std::basic_ifstream<char>’
 5028 |   auto ifs = std::basic_ifstream<Char>{ str };

Additional information

Solved by adding:

#include <fstream>

Generate CMake configuration file

Is your feature request related to a problem? Please describe.
It would be great if tomlplusplus could install a CMake config file to permit downstream users to use it in CMake by simply:

find_package(tomlplusplus REQUIRED)

// ...

target_link_libraries(<downstream_target> PRIVATE tomlplusplus::tomlplusplus)

Describe the solution you'd like
I think this is possible by using meson support for writing CMake configuration files, see https://mesonbuild.com/CMake-module.html#cmake-configuration-files .

Describe alternatives you've considered
The alternative is to leave to downstream users to write and install a Findtomlplusplus.cmake file, see ami-iit/bipedal-locomotion-framework#26 (comment)

Additional context
Depending on wheter we end up using toml++ in our projects, I may be happy to work on it myself. This should also simplify the integration of toml++ in vcpkg (see microsoft/vcpkg#10667).

cc @GiulioRomualdi @S-Dafarra

value::operator == for doubles is missing some cases

This bit:

switch (pack(impl::fpclassify(lhs.val_), impl::fpclassify(rhs)))
{
    case pack(fp_class::pos_inf, fp_class::neg_inf):    [[fallthrough]];
    case pack(fp_class::pos_inf, fp_class::nan):        [[fallthrough]];
    case pack(fp_class::neg_inf, fp_class::pos_inf):    [[fallthrough]];
    case pack(fp_class::neg_inf, fp_class::nan):        [[fallthrough]];
    case pack(fp_class::nan, fp_class::pos_inf):        [[fallthrough]];
    case pack(fp_class::nan, fp_class::neg_inf):
        return false;

    case pack(fp_class::pos_inf, fp_class::pos_inf):    [[fallthrough]];
    case pack(fp_class::neg_inf, fp_class::neg_inf):    [[fallthrough]];
    case pack(fp_class::nan, fp_class::nan):
        return true;

    case pack(fp_class::ok, fp_class::ok):
        return lhs.val_ == rhs;

    TOML_NO_DEFAULT_CASE;
}

If I'm not mistaken, it's missing any cases for comparing an ok against any of the non-ok classes?

Also....why is this whole thing here? 😅 Regular floating-point comparison will do what you want in all the cases here except for nan == nan which always returns false, while you have it as true (and I'd argue it's better not to change the semantics there unexpectedly, unless you have a very good reason to do so).

Copying nodes

Is your feature request related to a problem? Please describe.
I am currently in the process of replacing a json library with your toml library, and I have encountered this issue a couple times, where I needed to make a copy of a node. In the first case, I was able to do a move. In other cases, I need a copy.
Specifically, I have a table with one element that is an array. I want to be able to copy that array to a second element in that table.

Existing table:
[table]
foo = [1, 2, 3]

In pseudo-code:
auto *array = table.get("foo");
table["bar"] = *array;

Describe the solution you'd like
I am pretty that I can accomplish this by manually iterating over the elements in the toml::node.

Describe alternatives you've considered
I was surprised to find that copy constructors were deleted.

Additional context
Are there, or will there be any plans to include node copying in the future?

_Float16 is not present on g++

the _Float16 type is not present on arm g++

Environment

g++ 7.4 7.5 and others

C++ standard mode (e.g. 17, 20, 'latest'):
not applicable

Target arch (e.g. x64):
arm64, arm

Library configuration overrides:
not applicable

Relevant compilation flags:
see steps to reproduce link

Describe the bug

_Float16 is not available desptite gcc documentation saying one should use it
It's only available for C not C++

Steps to reproduce (or a small repro code sample)

https://godbolt.org/z/5e6rdP
The last one shows it's visible for C

Additional information

Better TOML_EXCEPTIONS=0 support

Is your feature request related to a problem? Please describe.
I'm in the middle of transitioning from some exceptions to no exceptions in my code base. I switched my old toml parser to toml++, but I'm currently still in the process of rewriting the rest of my code base. Since I'm still working on that, I opted into taking toml++ but using the TOML_EXCEPTIONS=0 setting in my cmake file.

toml++ tries to be intelligent and automatically determine the value of TOML_EXCEPTIONS based on a few things:

https://github.com/marzer/tomlplusplus/blob/master/include/toml%2B%2B/toml_common.h#L147-L157

#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)

However this completely brakes my use case, and I have to change toml_common.h to disable these checks.

Describe the solution you'd like
I propose adding a #ifndef TOML_EXCEPTIONS around this test, that way if the user (me) has explicitly opted for one way or the other, the library doesn't try and do anything automatically.

Describe alternatives you've considered
none

toml parser cuts off the first letter of the first key on the first line

Environment

Compiler:

g++ 9.3 Ubuntu

C++ standard mode (e.g. 17, 20, 'latest'):

C++17

Target arch (e.g. x64):

x86_64 for wsl

Library configuration overrides:

TOML_EXCEPTIONS=0

Relevant compilation flags:

-fno-exceptions -fno-rtti

Describe the bug

when a toml file has no newlines or spaces before the first key the first letter is cut off

Steps to reproduce (or a small repro code sample)

test.toml

jeff = "name"
auto it = toml::parse_file("test.toml");
auto tab = std::move(it).get();

auto jeff = tab["jeff"].value_or<std::string>("no"sv);
print(jeff); // prints "no" instead of "name"

Additional information

im using WSL on windows 2004

More documentation!

Writing documentation is kinda hard. Coming up with nice examples in said documentation is even harder. This will be an ongoing issue for me, and I welcome any contributions!

changing data in table

Hallo,

I wished there were a possibility to mutate the data inside the table. Or creating toml tables from scratch; similar to nlohmann json library.

e.g.
toml::table newtable;
newtable["mycat"]["myvalue"] = "Please insert Value Here";

tomplusplus fails to compile with msvc 2017

Environment

Compiler:
MSVC2017

C++ standard mode (e.g. 17, 20, 'latest'):
c++17

Target arch (e.g. x64):
x64

Library configuration overrides:

Relevant compilation flags:
/permissive-

Describe the bug

bug 1

__has_cpp_attribute is a c++20 feature
in toml_preprocessor.h there is no check for this

bug 2

cast operators in array_iterator and table_iterator are not liked by msvc, because of [[nodiscard]]

template <bool C = IsConst, typename = std::enable_if_t<!C>>
[[nodiscard]]
array_iterator<true>() const noexcept
{
    return array_iterator<true>{ raw_ };
}

see https://godbolt.org/z/Kvdrd3
the problem is fixed in 19.20 (_MSC_VER >= 1920)

Preserving original order

Is your feature request related to a problem? Please describe.

Hi

Is there a way to preserve original order of toml file?
After parse() and serialization(cout << parsed_toml_node), the order in output is different to the original file.
It seems like toml++ reorder according to alphabetical order of key name.
Can you recommend a way to preserve original order of toml file?

Describe the solution you'd like

Additional context

Installed pkg-config contains the wrong include directory

Environment

Compiler:
MSVC 2019

C++ standard mode (e.g. 17, 20, 'latest'):
C++17

Target arch (e.g. x64):
x64

Describe the bug

The generated pkg-config .pc is the following:

$ cat toml++.pc
prefix=C:/src/tomlplusplus/build/install
libdir=${prefix}/lib
includedir=${prefix}/include

Name: toml++
Description: Header-only TOML config file parser and serializer for modern C++
Version: 1.1.0
Cflags:-I${includedir}/toml++

and it specifies that include directories are C:/src/tomlplusplus/build/install/toml++, meaning that a user should include toml++'s headers as:

#include <toml.h>

while according to the readme (https://github.com/marzer/tomlplusplus#-regular-flavour) the correct way of including them is:

#include <toml++/toml.h>

So I guess that we should drop the subdirs argument from https://github.com/marzer/tomlplusplus/blob/764e6dd032fe67b6434183c0510e36b820498de6/meson.build, that do you think @marzer @ximion ?

Additional information

toml::parse_file rises too many initializers for 'std::basic_ifstream<char>' error

Environment

Compiler: g++.exe (Rev2, Built by MSYS2 project) 9.2.0

C++ standard mode: C++20

Target arch: x64

Exceptions enabled: Yes

Relevant toml++ configuration customizations: No

Relevant compilation flags: Debug symbols are enabled

Using conan along cmake:

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

And the conanfile:

[requires]
imgui/1.74
glfw/3.3.2@bincrafters/stable
glew/2.1.0@bincrafters/stable
glm/0.9.9.8
bullet3/2.89
spdlog/1.5.0
fmt/6.2.0

[generators]
cmake

Describe the bug

Using this:

void load(const char* file)
{
  auto toml::parse_file(file);
}

Causes:

/src/headers/toml.hpp: In instantiation of 'toml::parse_result toml::abi_parse_ex::parse_file(std::basic_string_view<Char>) [with Char = char; toml::parse_result = toml::table]':
/src/headers/toml.hpp:5953:20:   required from 'toml::parse_result toml::abi_parse_ex::parse_file(const Char*) [with Char = char; toml::parse_result = toml::table]'
/src/cpp/my-file.cpp, line numbers... required from here
src/headers/toml.hpp:5923:8: error: too many initializers for 'std::basic_ifstream<char>'
 5923 |   auto ifs = std::basic_ifstream<Char>{ str };
      |        ^~~

Add node_view::value_or()

To turn this:

auto fval = tbl[key][0].as_floating_point() ? **tbl[key][0].as_floating_point() : 0.0f

Into this:

auto fval = tbl[key][0].value_or(0.0f);

parse_file fails with raw `char const*`

Environment

Compiler:
Clang 11

C++ standard mode (e.g. 17, 20, 'latest'):
C++20

Target arch (e.g. x64):
x64

Exceptions enabled:
DISABLED

Relevant toml++ configuration customizations:
I use a proxy-header for including toml to help with warnings

#pragma once
#pragma GCC system_header
#pragma clang system_header

#include <toml++/toml.h>

Relevant compilation flags:

-Wall;-Werror;-Wextra;-Wmissing-field-initializers;-Wno-padded;-Wno-deprecated;-Wno-shadow-uncaptured-local;-fdiagnostics-color;-fcolor-diagnostics;-fcaret-diagnostics;-Wpedantic;-Weverything;-Wno-gnu-statement-expression;-Wno-reserved-id-macro;-Wno-c++98-compat;-Wno-c++98-compat-pedantic;-Wno-global-constructors;-Wno-newline-eof;-Wno-pragma-once-outside-header;-Wno-documentation;-Wno-documentation-unknown-command;-Wno-missing-prototypes;-Wswitch;-Wno-switch-enum;-Wno-ignored-attributes;-fno-inline;-fno-omit-frame-pointer;-fno-optimize-sibling-calls;-O0;-g0

Describe the bug

Passing a raw char const* to parse_file fails to compile with the following error:

error: no matching function for call to 'parse_file'
auto presult = toml::parse_file("levels/resources.toml");
^~~~~~~~~~~~~~~~
../external/toml++/toml_parser.h:369:22: note: candidate template ignored: could not match 'basic_string_view<type-parameter-0-0, char_traits >' against 'const char *'
inline parse_result parse_file(std::basic_string_view file_path) TOML_MAY_THROW

Additional information

I can work around this by manually wrapping my raw char const* with a std::string_view, but this code is shown working in the README.md file (which is why I filed it as a bug, not a feature request).

Potential Fix

Here's the work-around I added to my local copy of toml++, maybe it will be helpful.

inline parse_result parse_file(char const* file_path) TOML_MAY_THROW
{
	auto ifs = std::basic_ifstream<char>{ file_path };
	return parse(
		ifs,
		std::string_view{ file_path, std::strlen(file_path) }
	);
}

Improve `node` and `node_view` interfaces

Is your feature request related to a problem? Please describe.
The node_view could be made more similar to a std::optional to enhance usability.
Also, there's no clean way to extract a generic "number" which can be floating or integer: currently I have to do

if (node.is_floating_point()) {
    return node.as_floating_point()->get();
}
else if (node.is_integer()) {
    return node.as_integer()->get();
}
else {
    ....
}

I know that there's a .is_number() member function, It would be great to have a way to directly extract the number, for example:

if (node.is_number()) {
    return node.get_number();
} else {
    ....
} 

In general, it would be great to have a shorter way to get values from a node

Describe the solution you'd like
I think it would be useful to:

  • make node_view more like optional: it currently has a .value_or() member function, but not a throwing .value(), nor a .has_value(), for example.
  • equip node with a member function which return the number it contains, whether it is an integer or a floating point
  • equip node with a member function which returns the value directly or inside an (eventually empty) optional or node_view (which in my opinion are more expressive than a pointer)

Describe alternatives you've considered
For the second issue, an alternative could be make .as_floating_point()->get() implicitly convert the underlying integer, making the following code work:

if (node.is_number()) {
    return node.as_floating_point()->get();
}

is_unicode_letter and is_unicode_number may be incomplete

Related issue: toml-lang/toml#766

Presently, running https://gist.github.com/marzer/e7649c763cf4522686f85812f06022aa results in letters having 131230 codepoints in total, numbers having 886 codepoints in total, and combining_marks having 2282 codepoints in total.

In contrast, is_unicode_letter says it only checks 131189 and is_unicode_number only checks 876. is_unicode_combining_mark says it checks 2282 codepoints, which is all good!

Is there any way to get your python script to output C++ code in the format of your function?

How to insert a none value into a table?

Hi,

Thinking about this example,

toml::table t;
t.insert_or_assign("a", ...)

What should I fill in the ... part to get a assigned to a none value? Seems toml::value's constructor does not explicitly support me to construct such a value.

Thanks for any help!

Bob

TOML serialization to ofstream and newline behavior

Environment

Compiler:
Visual Studio 2019 16.6.3

C++ standard mode (e.g. 17, 20, 'latest'):
C++17

Target arch (e.g. x64):
x86

Exceptions enabled:
Yes

Relevant toml++ configuration customizations:
TOML_EXCEPTIONS=0

Relevant compilation flags:
N/A

Describe the bug

When serializing TOML to a std::ofstream an extraneous newline is always inserted at the start of file even if it wasn't there, and a newline is always missing at the last line of the file.

I trust it you won't need a code sample or steps to reproduce for this one.

Lack of last newline can be solved by myfile << endl; after serialization but removing the empty one at the start is not possible.

Note that any inserted table has proper newline added before it, but maybe there should be special case of alphabetically first table in the file not having a leading newline unless there are values that belong to the file scope before?

Add support for std::wstring

Replace the italic text below with the relevant information to help me understand your request.

Is your feature request related to a problem? Please describe.
Currently if you want to pass wchar_t * or std::wstring as either key name or a string value, or read into std::wstring you must do the conversion to and from UTF-8 explicitly. This makes the library rather hard to use with Windows API, especially with DirectShow, DirectX, DirectWrite, Direct2D and other COM-based Win32 interfaces, including all OS API ending with W. Use of ANSI API is definitely discouraged nowadays so the only option at the moment is to do the necessary conversions yourself.

Describe the solution you'd like
I would appreciate if your library would natively support std::wstring for value keys, file paths, string serialization/deserialization, doing all the wide string to UTF-8 (and vice versa) conversions in the background as needed.

Describe alternatives you've considered
I don't see any good alternatives to native support for std::wstring.

Additional context
N/A

iterator proxy pair ought to decay to value semantics on demand

Lots of generic STL code would always do:

for(auto &i : container)

This prevents the value copy of items being iterated. You have proxy pair in place to prevent this occurring for:

for(auto i : container)

Firstly, any compiler which is not MSVC will elide that copy under optimisation if i never escapes or is modified. So your proxy optimisation probably doesn't actually save much, except on MSVC.

Meanwhile, the lack of value sematics for the second for loop causes much generic code to break. If the code asked for a copy, it expects an as-if copy. If you wish to retain your proxy, you ought to have it implicitly convert to a value type upon demand in order to retain expected semantics.

Conversion from double to string is locale-dependent if TOML_FLOATING_POINT_CHARCONV is 0

Environment

Compiler:
Any compiler that does not support to_chars for double , i.e. for which TOML_FLOATING_POINT_CHARCONV is 0.

C++ standard mode (e.g. 17, 20, 'latest'):
17

Target arch (e.g. x64):
Not relevant.

Exceptions enabled:
Not relevant.

Relevant toml++ configuration customizations:
Not relevant.

Relevant compilation flags:
Not relevant.

Describe the bug

When TOML_FLOATING_POINT_CHARCONV std::ostringstream is used to convert a double to a string in https://github.com/marzer/tomlplusplus/blob/v1.1.0/include/toml++/toml_parser_impl.h#L153 . However, the imbue method is not called, so the default locale, that is the global C++ locale set in https://en.cppreference.com/w/cpp/locale/locale/global . If it is intended to have the same behavior independently from the value TOML_FLOATING_POINT_CHARCONV, I guess it is necessary to call ss.imbue(std::locale::classic()); after the ss object is declared. I did not checked other code paths if TOML_FLOATING_POINT_CHARCONV is set to 0, but it is possible that they are affected as well.

Additional information

Related issues:

cc @S-Dafarra @GiulioRomualdi

Detection of (and testing with) other compilers

ICC, for example. I don't have ready access to it so it makes testing for it a bit challenging.

I could use something like Hedley but I'd like to keep toml++ self-contained. Cherry-picking from hedley is on option too, of course (with appropriate attribution obviously).

A python wrapper!

Hi,

Maybe I am getting excited too early but I have made a python wrapper for this awesome library, here is my repo: https://github.com/bobfang1992/pytomlpp

I have done the deserializing part but has yet to do the serializing part. But its taking shape quite fast.

This is just more like to inform you about this. If you have any comments I am happy to know.

Best,
Bob

Preservation of comments and whitespace

Firstly, this is one of those very few libraries I've used where I don't think I'd have done much different myself. Well, possibly I'd have made it always non-throwing. Well done on that, and thank you for making it open source.

Another thing that I would have done is optional comment and whitespace preservation, such that if you read in a TOML file, and then write it out, comments and whitespace are preserved. This is useful because I'm using your library a bit like how clang-tidy or doxygen do things, where you can dump out a default TOML config, hand edit it, or supply TOML delta files to merge against the default TOML config, and so on. Therefore, dumping out the post-merge TOML file, with all comments also merged, would be ideal.

For this to work right, you'd need to retain comments and whitespace as an attribute of the first node following the comment. Then, if the node gets replaced by a merge, one could retain the existing comment and whitespace, or replace it with the new comment and whitespace etc.

I'd personally make this opt-in, as plenty of people don't want to waste CPU nor memory on comments and whitespace. My thanks in advance to you for your consideration!

Static analyser fail due to potential array index out of bounds

This is against tagged release v1.2.5:

/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:69: error: The right operand of '==' is a garbage value due to array index out of bounds [clang-analyzer-core.UndefinedBinaryOperatorResult,-warnings-as-errors]
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                                                                       ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_parser.h:497:10: note: Calling 'parse<char>'
                return parse( ifs, std::move(str) );
                       ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_parser.h:463:25: note: Calling constructor for 'utf8_reader<std::basic_istream<char>>'
                return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
                                      ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:230:7: note: Calling constructor for 'utf8_byte_stream<std::basic_istream<char>>'
                                : stream{ std::forward<U>(source) }
                                  ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:79:9: note: Calling 'basic_ios::operator bool'
                                if (*source)
                                    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Calling 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:16: note: Assuming the condition is false
      { return (this->rdstate() & (badbit | failbit)) != 0; }
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:9: note: Returning zero, which participates in a condition later
      { return (this->rdstate() & (badbit | failbit)) != 0; }
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Returning from 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:9: note: Returning the value 1, which participates in a condition later
      { return !this->fail(); }
        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:79:9: note: Returning from 'basic_ios::operator bool'
                                if (*source)
                                    ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:79:5: note: Taking true branch
                                if (*source)
                                ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Calling 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Calling 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:16: note: Assuming the condition is false
      { return (this->rdstate() & (badbit | failbit)) != 0; }
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:9: note: Returning zero, which participates in a condition later
      { return (this->rdstate() & (badbit | failbit)) != 0; }
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Returning from 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:9: note: Returning the value 1, which participates in a condition later
      { return !this->fail(); }
        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Returning from 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:24: note: Assuming the condition is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                          ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:60: note: Assuming the condition is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                                                              ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:6: note: Loop condition is true.  Entering loop body
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Calling 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Calling 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:16: note: Assuming the condition is false
      { return (this->rdstate() & (badbit | failbit)) != 0; }
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:9: note: Returning zero, which participates in a condition later
      { return (this->rdstate() & (badbit | failbit)) != 0; }
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Returning from 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:9: note: Returning the value 1, which participates in a condition later
      { return !this->fail(); }
        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Returning from 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:24: note: Assuming the condition is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                          ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:60: note: Assuming the condition is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                                                              ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:6: note: Loop condition is true.  Entering loop body
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Calling 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Calling 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:16: note: Assuming the condition is false
      { return (this->rdstate() & (badbit | failbit)) != 0; }
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:9: note: Returning zero, which participates in a condition later
      { return (this->rdstate() & (badbit | failbit)) != 0; }
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Returning from 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:9: note: Returning the value 1, which participates in a condition later
      { return !this->fail(); }
        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Returning from 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:24: note: Assuming the condition is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                          ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:60: note: Assuming the condition is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                                                              ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:6: note: Loop condition is true.  Entering loop body
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:93:7: note: The value 3 is assigned to 'bom_pos'
                                                bom_pos++;
                                                ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Calling 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Calling 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:16: note: Assuming the condition is false
      { return (this->rdstate() & (badbit | failbit)) != 0; }
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:202:9: note: Returning zero, which participates in a condition later
      { return (this->rdstate() & (badbit | failbit)) != 0; }
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:17: note: Returning from 'basic_ios::fail'
      { return !this->fail(); }
                ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/basic_ios.h:118:9: note: Returning the value 1, which participates in a condition later
      { return !this->fail(); }
        ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Returning from 'basic_ios::operator bool'
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:24: note: Assuming the condition is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                          ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:13: note: Left side of '&&' is true
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                               ^
/home/ned/.hunter/_Base/017e688/6891967/9d1c865/Install/include/toml++/toml_utf8_streams.h:91:69: note: The right operand of '==' is a garbage value due to array index out of bounds
                                        while (*source && bom_char != stream_traits::eof() && bom_char == bom[bom_pos])
                                                                                                       ^
1 warning generated.
1 warning treated as error

[help] How to iterate a table

[table]
a = 1
b = 2
c = 3
  #include "toml.hpp"

  auto config = toml::parse_file("config.toml");
  auto table = config["table"];
  std::cout << "type=" << table.type() << "\n";
  std::cout << "is_table=" << table.is_table() << "\n";
  //for (auto [k, v] : table) {
  //}

Output tells it is a table, but compiler complains about the for loop:

src/main.cpp:69:22: error: ‘begin’ was not declared in this scope; did you mean ‘std::begin’?
   69 |   for (auto [k, v] : table) {
      |                      ^~~~~
      |                      std::begin
In file included from /opt/rh/gcc-toolset-9/root/usr/include/c++/9/string:54,
                 from /opt/rh/gcc-toolset-9/root/usr/include/c++/9/bits/locale_classes.h:40,
                 from /opt/rh/gcc-toolset-9/root/usr/include/c++/9/bits/ios_base.h:41,
                 from /opt/rh/gcc-toolset-9/root/usr/include/c++/9/ios:42,
                 from /opt/rh/gcc-toolset-9/root/usr/include/c++/9/ostream:38,
                 from /opt/rh/gcc-toolset-9/root/usr/include/c++/9/iostream:39,
                 from src/main.cpp:5:
/opt/rh/gcc-toolset-9/root/usr/include/c++/9/bits/range_access.h:105:37: note: ‘std::begin’ declared here
  105 |   template<typename _Tp> const _Tp* begin(const valarray<_Tp>&);
      |                                     ^~~~~

iterators returned during iteration ought to also implement first and second

Right now, iterators of tables return a value item with key and value.

It would suit genericity better if they also contained first and second, to match the STL. This may appear to double the size of the proxy pair, but if you place them last in the structure, and consuming code doesn't use them, you'll find GCC and clang elide the storage for them under optimisation. They therefore become "free".

error: undefined symbol: toml::abi_parse_ex::parse(

This toml++ HEAD from yesterday. I am very new to toml++ so likely this is my mistake somewhere. I have been building with the same configuration a long time previously without toml++.

Environment

Clang 10 -c++17, 2a

Target arch (e.g. x64):
x64

Exceptions enabled:
Yes, by default

Relevant toml++ configuration customizations:
hpp:
#define TOML_ALL_INLINE 0
#define TOML_API attribute ((visibility("default")))
#include <toml.hpp>

cpp:
#include <header-that-includes-toml.hpp>
#define TOML_IMPLEMENTATION
#include <toml.hpp>

Relevant compilation flags:

The visibility options are included with:

clang++10 -Icore/nail/9f7356c@@nail@sha -Icore/nail -I../core/nail -Icore -I../core -I../subprojects/optionparser/include -I../subprojects/pcg/include -I../subprojects/tomlplusplus/include -Xclang -fcolor-diagnostics -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -O3 -fstack-protector -fvisibility=hidden -fvisibility-inlines-hidden -fPIC -MD -MQ 'core/nail/9f7356c@@nail@sha/config_manager.cpp.o' -MF 'core/nail/9f7356c@@nail@sha/config_manager.cpp.o.d' -o 'core/nail/9f7356c@@nail@sha/config_manager.cpp.o' -c ../core/nail/config/manager.cpp

Describe the bug

I'm not getting any toml:: symbols at all from the cpp file:

nm -C config_manager.cpp.o | grep toml
0000000000000000 W nail::config::manager_impl::register_toml_handler(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator > const&, std::__1::function<void (toml::node*)>)
U nail::config::toml_processor::make(nail::config::command_line_processor&)

That's my own symbol. And linking the shared lib from the file produces:
error: undefined symbol: toml::abi_parse_ex::parse([string_view, string_view])

And then goes on to complain about a missing key function but I guess that would toml::parse().

Apparently there's an interaction with inlines/visibility that I don't understand.

MSVC 19 C2666 error: 'toml::v2::operator ==': 2 overloads have similar conversions

Environment

Compiler: MSVS 19

C++ standard mode: 17

Target arch: x64

Library configuration overrides: None

Describe the bug

Trying to compile library using tomlplusplus v2.1.0 causes c2666 to appear:

Multiple headers
toml++\toml_value.h(439): error C2666: 'toml::v2::operator ==': 2 overloads have similar conversions
toml++\toml_table.hpp(283): note: could be 'bool toml::v2::operator ==(const toml::v2::table &,const toml::v2::table &) noexcept' [found using argument-dependent lookup]
toml++\toml_array.hpp(206): note: or       'bool toml::v2::operator ==(const toml::v2::array &,const toml::v2::array &) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\exception(267): note: or       'bool std::operator ==(const std::exception_ptr &,const std::exception_ptr &) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\exception(271): note: or       'bool std::operator ==(std::nullptr_t,const std::exception_ptr &) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\exception(275): note: or       'bool std::operator ==(const std::exception_ptr &,std::nullptr_t) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\system_error(168): note: or       'bool std::operator ==(const std::error_code &,const std::error_code &) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\system_error(172): note: or       'bool std::operator ==(const std::error_code &,const std::error_condition &) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\system_error(176): note: or       'bool std::operator ==(const std::error_condition &,const std::error_code &) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\system_error(248): note: or       'bool std::operator ==(const std::error_condition &,const std::error_condition &) noexcept' [found using argument-dependent lookup]
MSVC\14.27.29110\include\thread(204): note: or       'bool std::operator ==(std::thread::id,std::thread::id) noexcept' [found using argument-dependent lookup]
toml++\toml_common.h(768): note: or       'bool toml::v2::sf::operator ==(const toml::v2::sf::source_position &,const toml::v2::sf::source_position &) noexcept' [found using argument-dependent lookup]
toml++\toml_date_time.h(23): note: or       'bool toml::v2::operator ==(toml::v2::date,toml::v2::date) noexcept' [found using argument-dependent lookup]
toml++\toml_date_time.h(113): note: or       'bool toml::v2::operator ==(const toml::v2::time &,const toml::v2::time &) noexcept' [found using argument-dependent lookup]
toml++\toml_date_time.h(230): note: or       'bool toml::v2::operator ==(toml::v2::time_offset,toml::v2::time_offset) noexcept' [found using argument-dependent lookup]
toml++\toml_date_time.h(350): note: or       'bool toml::v2::stdopt::operator ==(const toml::v2::stdopt::date_time &,const toml::v2::stdopt::date_time &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(451): note: or       'bool toml::v2::node_view<toml::v2::node>::operator ==(const toml::v2::node_view<toml::v2::node> &,const toml::v2::table &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(458): note: or       'bool toml::v2::node_view<toml::v2::node>::operator ==(const toml::v2::table &,const toml::v2::node_view<toml::v2::node> &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(462): note: or       'bool toml::v2::node_view<toml::v2::node>::operator ==(const toml::v2::node_view<toml::v2::node> &,const toml::v2::array &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(469): note: or       'bool toml::v2::node_view<toml::v2::node>::operator ==(const toml::v2::array &,const toml::v2::node_view<toml::v2::node> &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(451): note: or       'bool toml::v2::node_view<const toml::v2::node>::operator ==(const toml::v2::node_view<const toml::v2::node> &,const toml::v2::table &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(458): note: or       'bool toml::v2::node_view<const toml::v2::node>::operator ==(const toml::v2::table &,const toml::v2::node_view<const toml::v2::node> &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(462): note: or       'bool toml::v2::node_view<const toml::v2::node>::operator ==(const toml::v2::node_view<const toml::v2::node> &,const toml::v2::array &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(469): note: or       'bool toml::v2::node_view<const toml::v2::node>::operator ==(const toml::v2::array &,const toml::v2::node_view<const toml::v2::node> &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(395): note: or       'bool toml::v2::value<std::string>::operator ==(const toml::v2::value<std::string> &,std::basic_string_view<char,std::char_traits<char>>) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(408): note: or       'bool toml::v2::value<std::string>::operator ==(std::basic_string_view<char,std::char_traits<char>>,const toml::v2::value<std::string> &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(395): note: or       'bool toml::v2::value<int64_t>::operator ==(const toml::v2::value<int64_t> &,__int64) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(408): note: or       'bool toml::v2::value<int64_t>::operator ==(__int64,const toml::v2::value<int64_t> &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(395): note: or       'bool toml::v2::value<double>::operator ==(const toml::v2::value<double> &,double) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(408): note: or       'bool toml::v2::value<double>::operator ==(double,const toml::v2::value<double> &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(395): note: or       'bool toml::v2::value<bool>::operator ==(const toml::v2::value<bool> &,bool) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(408): note: or       'bool toml::v2::value<bool>::operator ==(bool,const toml::v2::value<bool> &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(395): note: or       'bool toml::v2::value<toml::v2::date>::operator ==(const toml::v2::value<toml::v2::date> &,const toml::v2::date &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(408): note: or       'bool toml::v2::value<toml::v2::date>::operator ==(const toml::v2::date &,const toml::v2::value<toml::v2::date> &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(395): note: or       'bool toml::v2::value<toml::v2::time>::operator ==(const toml::v2::value<toml::v2::time> &,const toml::v2::time &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(408): note: or       'bool toml::v2::value<toml::v2::time>::operator ==(const toml::v2::time &,const toml::v2::value<toml::v2::time> &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(395): note: or       'bool toml::v2::value<toml::v2::stdopt::date_time>::operator ==(const toml::v2::value<toml::v2::stdopt::date_time> &,const toml::v2::stdopt::date_time &) noexcept' [found using argument-dependent lookup]
toml++\toml_value.h(408): note: or       'bool toml::v2::value<toml::v2::stdopt::date_time>::operator ==(const toml::v2::stdopt::date_time &,const toml::v2::value<toml::v2::stdopt::date_time> &) noexcept' [found using argument-dependent lookup]
toml++\toml_node_view.h(481): note: or       'bool toml::v2::operator ==<std::string>(const toml::v2::value<std::string> &,const toml::v2::node_view<toml::v2::node> &) noexcept'
toml++\toml_node_view.h(489): note: or       'bool toml::v2::operator ==<ValueType,void>(const toml::v2::node_view<toml::v2::node> &,const T &) noexcept'
        with
        [
            ValueType=std::string,
            T=std::string
        ]
toml++\toml_node_view.h(481): note: or       'bool toml::v2::operator ==<std::string>(const toml::v2::value<std::string> &,const toml::v2::node_view<const toml::v2::node> &) noexcept'
toml++\toml_node_view.h(489): note: or       'bool toml::v2::operator ==<ValueType,void>(const toml::v2::node_view<const toml::v2::node> &,const T &) noexcept'
        with
        [
            ValueType=std::string,
            T=std::string
        ]
toml++\toml_value.h(439): note: while trying to match the argument list '(const toml::v2::value<std::string>, const ValueType)'
        with
        [
            ValueType=std::string
        ]
toml++\toml_array.hpp(222): note: see reference to function template instantiation 'bool toml::v2::operator ==<std::string>(const toml::v2::value<std::string> &,const toml::v2::value<std::string> &) noexcept' being compiled
toml++\toml_array.hpp(222): note: see reference to function template instantiation 'bool toml::v2::operator ==<std::string>(const toml::v2::value<std::string> &,const toml::v2::value<std::string> &) noexcept' being compiled
MSVC\14.27.29110\include\type_traits(1504): note: see reference to function template instantiation 'bool toml::v2::==::<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6>::operator ()<toml::v2::value<std::string>>(const toml::v2::value<std::string> &) noexcept const' being compiled
MSVC\14.27.29110\include\type_traits(1748): note: see reference to alias template instantiation 'std::_Decltype_invoke_nonzero<toml::v2::==::<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6>&&,toml::v2::value<std::string>&,>' being compiled
toml++\toml_node.h(553): note: see reference to variable template 'const bool is_invocable_v<<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6> &&,toml::v2::value<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > &>' being compiled
toml++\toml_node.h(581): note: see reference to variable template 'const bool toml::v2::node::can_visit<<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6> &&,toml::v2::node &,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >' being compiled
toml++\toml_node.h(588): note: see reference to variable template 'const bool toml::v2::node::visit_is_nothrow_one<<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6> &&,toml::v2::node &,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >' being compiled
toml++\toml_node.h(755): note: see reference to variable template 'const bool toml::v2::node::visit_is_nothrow<<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6> &&,toml::v2::node &>' being compiled
toml++\toml_node.h(754): note: while compiling class template member function 'bool toml::v2::node::visit<toml::v2::==::<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6>>(Func &&) noexcept &'
        with
        [
            Func=toml::v2::==::<lambda_e9cfa60f6d06c6107cbd5e52f5b441a6>
        ]
Single header (similar message)
toml.hpp(2848): error C2666: 'toml::v2::operator ==': 2 overloads have similar conversions
toml.hpp(8031): note: could be 'bool toml::v2::operator ==(const toml::v2::table &,const toml::v2::table &) noexcept' [found using argument-dependent lookup]
toml.hpp(7644): note: or       'bool toml::v2::operator ==(const toml::v2::array &,const toml::v2::array &) noexcept' [found using argument-dependent lookup]
[snip]

Works fine in v2.0.0

toml table to string/file?

Is your feature request related to a problem? Please describe.
I have a Problem. How can I convert a toml::table to string, so I can save it as file?

Describe the solution you'd like
a function dump() which returns the string to save it to a file or a direct function table.saveFile

Describe alternatives you've considered
Need to code a work around with for loops

C++20 MSVC Syntax Error [CMake]

Environment

Compiler:
MSVC

C++ standard mode (e.g. 17, 20, 'latest'):
C++20

Target arch (e.g. x64):
x64

Exceptions enabled:
I am using the default (/EHsc) Exceptions

Relevant toml++ configuration customizations:
No overrides are used

Relevant compilation flags:
None

Describe the bug

Syntax/Unknown-Type/Traits errors.

toml.hpp(8103): error C2589: '(': illegal token on right side of '::'
toml.hpp(8612): note: see reference to function template instantiation 'int64_t toml::impl::abi_impl_noex::parser::parse_integer<16>(void) noexcept' being compiled
toml.hpp(8103): error C2062: type 'unknown-type' unexpected
toml.hpp(8103): error C2144: syntax error: 'unknown-type' should be preceded by '('
toml.hpp(8103): error C2059: syntax error: ')'
toml.hpp(8104): error C2143: syntax error: missing ';' before '{'
toml.hpp(8104): error C2059: syntax error: ','
toml.hpp(8104): error C2059: syntax error: ')'
toml.hpp(8104): error C2059: syntax error: 'return'
toml.hpp(8104): error C2059: syntax error: '}'
toml.hpp(8108): error C2059: syntax error: 'if'
toml.hpp(8108): error C2653: 'traits': is not a class or namespace name
toml.hpp(8110): error C2059: syntax error: 'else'
toml.hpp(8112): error C2059: syntax error: '}'
toml.hpp(8112): error C2143: syntax error: missing ';' before '}'

Steps to reproduce (or a small repro code sample)

Include it in any source file.

Additional information

Screenshots of the compiler error:
image

array insertion fails const iterator conversion

toml::array to, from;
for(size_t n = 0; n < from.size(); n++)
{
  to.insert(to.end(), std::move(from[n]));  // fails with cannot convert argument 1 from 'toml::array::iterator' to 'toml::array::const_iterator'
}

Solve the ODR problem between exception handling modes

A redditor pointed out that altering function signatures according to exception handling mode may cause ODR issues in complex dependency situations.

The suggestion for resolving this issue was to provide differently-named functions based on the exception semantics (e.g. toml::parse, toml::parse_noexcept). I very highly value the simplicity and uniformity of the API so I don't think I'll go down this route. Instead I can solve the issue and keep a uniform API by instead quarantining the ABI according to exception mode using inline namespaces.

Empty file is valid toml file

Hi,

Just want to mention that from what I can see, most toml parser implementation will be happy to take an empty file as input instead of raise but tomlplusplus seems to be doing the opposite. I would think this is not a bug but just different choices made by the developer. In my humble opinion, I think returning an empty table, in this case, is not outrageous compared to raising a run time error as tomlplusplus does now.

Happy to hear your thought.

Bob

Allow serialization of literal strings using single quotes

Replace the italic text below with the relevant information to help me understand your request.

Is your feature request related to a problem? Please describe.
Currently it is not possible to serialize say a system path such as C:\Path\To\Some\File.txt into literal TOML string. Instead, the strings are escaped and put in double quotes which makes them hard for humans to read and edit which is countering the main advantage of using TOML in the first place.

Describe the solution you'd like
Make it possible to output raw, unescaped, strings with single quotes.

Describe alternatives you've considered
I don't see any alternative to supporting one of the crucial TOML features.

Additional context
N/A

"key = -1" parses as "key = 1"

If you examine https://github.com/marzer/tomlplusplus/blob/master/include/toml%2B%2B/toml_parser.hpp#L1950:

						// single-digit signed integers
						if (char_count == 2_sz && has_any(has_digits))
						{
							val = std::make_unique<value<int64_t>>(
								static_cast<int64_t>(chars[1] - U'0')
								* (chars[1] == U'-' ? -1LL : 1LL)
							);
							advance(); //skip the sign
							advance(); //skip the digit
							break;
						}

... the check for the minus sign is wrong, it should be checking chars[0], not chars[1]. Hence all negative numbers in TOML become positive!

Allow serializing numbers as hex, octal, or binary for readability

Is your feature request related to a problem? Please describe.
Currently it does not seem possible to control serialization of numbers in the library. TOML specification allows numbers to be specified with 0x, 0o, and 0b prefixes. This is a great advantage over other file formats because it allows for serialization of things like hex RGBA color values, Unix permissions, and bitfields/flags in a human-readable format.

Describe the solution you'd like
Implement some way of specifying the number format for insert() and insert_or_assign() methods.

Describe alternatives you've considered
I am not aware of any alternatives.

Additional context
N/A

How to retrieve the C++ underlying value (string, double, integer, bool...)?

Hey there,
I came accross your lib, and the documentation doesn't cover how to retrieve the stored data.
I'm reading a configuration file, and need to retrieve a string here, a flot there, but std::string spriteSheet = table["data"]["spriteSheet"].get() is saying that it can't convert a node* to a string, with

[data]
spriteSheet="hello.gif"

Thanks in advance

Deserialization of arrays into std::vector and std::map

A few ideas:

Idea 1:

Signature = [ 0x44, 0x4F, 0x53, 0x00 ]

Deserialize into std::vector<uint8_t> or std::vector<uint16_t> or std::vector<uint32_t> or std::vector<uint64_t> or their signed counterparts?

Idea 2:

Signature = [ 'M', 'S', 'C', 'F' ]

Deserialize into std::string or std::wstring or std::vector<char> or std::vector<wchar_t>? I understand this one might be a problem because there is no guarantee that each array index will correspond to a single character.

Idea 3:

DenominationTable = { 33 = 1000, 30 = 100, 32 = 500, 34 = 2000 }

Deserialize into std::map<string, int> or std::map<wstring, int>?

Please let me know what you think.

Decide what to do with `node_view`

std::map's operator[] is a dumpster fire, so toml::table's operator[] doesn't work that way. Instead it spawns an instance of a proxy type, the node_view. Node views are structurally read-only (i.e. you can't assign to them directly to modify the type of the underlying node). We're using toml++ at my work and one of my colleagues suggested that he'd like to be able to do this:

auto tbl = toml::parse_file(/* ... */);
tbl["foo"][3] = 2.0;

Which looks lovely, but it raises some questions:

  1. What if tbl.foo didn't exist? Do we manifest it as an array?
  2. What if tbl.foo did exist, but wasn't an array? Does it get replaced with an array?
  3. What if tbl.foo was an array but didn't have 4 elements? Does it get filled with 'default' elements to fill the gap?
  4. If tbl.foo needed to be padded out to 4 elements, what type are the inserted values? Do we just default-construct additional instances of whatever the inserted type is?

I'm trying to err on the side of "principle of least astonishment" but honestly not sure what that would even be in these situations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.