cpptoml is a header-only library for parsing TOML

Overview

cpptoml

A header-only library for parsing TOML configuration files.

Targets: TOML v0.5.0 as of August 2018.

This includes support for the new DateTime format, inline tables, multi-line basic and raw strings, digit separators, hexadecimal integers, octal integers, binary integers, and float special values.

Alternatives:

  • Boost.toml is a C++ implementation of a TOML parser using the Boost library. As of writing, it supports v0.5.0 as well.
  • ctoml is a C++11 implementation of a TOML parser, but only supports v0.2.0.
  • libtoml is a C implementation of a TOML parser, which can be linked to from your C++ programs easily. As of April 2016, it supports v0.4.0.
  • tinytoml is a C++11 implementation of a TOML parser, which also supports v0.4.0 as of November 2015.

Build Status

Build Status

Test Results

From the toml-test suite:

126 passed, 0 failed

We also currently maintain (but hopefully not indefinitely!) a fork of the toml-test suite that adds tests for features and clarifications that have been added to the TOML spec more recently than toml-test has been updated. We pass every test there.

148 passed, 0 failed

Compilation

Requires a well conforming C++11 compiler. On OSX this means clang++ with libc++ and libc++abi (the default clang installed with XCode's command line tools is sufficient).

On Linux, you should be able to use g++ >= 4.8.x, or clang++ with libc++ and libc++abi (if your package manager supplies this; most don't).

Compiling the examples can be done with cmake:

mkdir build
cd build
cmake ../
make

Example Usage

To parse a configuration file from a file, you can do the following:

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

parse_file() returns a (shared pointer to a) cpptoml::table, which you can then query. It will throw an instance of cpptoml::parse_exception in the event that the file failed to parse, and the exception message should contain the line number the error occurred as well as a description of the error.

Obtaining Basic Values

You can find basic values like so:

auto val = config->get_as<int64_t>("my-int");
// val is a cpptoml::option<int64_t>

if (val)
{
    // *val is the integer value for the key "my-int"
}
else
{
    // "my-int" either did not exist or was not an integer
}

To simplify things, you can specify default a default value using the value_or function on the option:

auto baz = config->get_as<double>("baz").value_or(0.5);
// baz is now the double value for key "baz", if it exists, or 0.5 otherwise

cpptoml has extended support for dates and times beyond the TOML v0.4.0 spec. Specifically, it supports

  • Local Date (local_date), which simply represents a date and lacks any time information, e.g. 1980-08-02;
  • Local Time (local_time), which simply represents a time and lacks any date or zone information, e.g. 12:10:03.001;
  • Local Date-time (local_datetime), which represents a date and a time, but lacks zone information, e.g. 1980-08-02T12:10:03.001;
  • and Offset Date-time (offset_datetime), which represents a date, a time, and timezone information, e.g. 1980-08-02T12:10:03.001-07:00

Here are the fields of the date/time objects in cpptoml:

  • year (local_date, local_datetime, offset_datetime)
  • month (local_date, local_datetime, offset_datetime)
  • day (local_date, local_datetime, offset_datetime)
  • hour (local_time, local_datetime, offset_datetime)
  • minute (local_time, local_datetime, offset_datetime)
  • second (local_time, local_datetime, offset_datetime)
  • microsecond (local_time, local_datetime, offset_datetime)
  • hour_offset (offset_datetime)
  • minute_offset (offset_datetime)

There are convenience functions cpptoml::offset_datetime::from_zoned() and cpptoml::offset_datetime::from_utc() to convert struct tms to cpptoml::offset_datetimes.

Nested Tables

If you want to look up things in nested tables, there are two ways of doing this. Suppose you have the following structure:

[first-table]
key1 = 0.1
key2 = 1284

[first-table.inner]
key3 = "hello world"

Here's an idiomatic way of obtaining all three keys' values:

auto config = cpptoml::parse_file("config.toml");
auto key1 = config->get_qualified_as<double>("first-table.key1");
auto key2 = config->get_qualified_as<int>("first-table.key2");
auto key3 = config->get_qualified_as<std::string>("first-table.inner.key3");

(Note that, because the TOML spec allows for "." to occur in a table name, you won't always be able to do this for any nested key, but in practice you should be fine.)

A slightly more verbose way of getting them would be to first obtain the individual tables, and then query those individual tables for their keys like so:

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

auto first = config->get_table("first-table");
auto key1 = first->get_as<double>("key1");
auto key2 = first->get_as<int>("key2");

auto inner = first->get_table("inner");
auto key3 = inner->get_as<std::string>("key3");

The function get_table_qualified also exists, so obtaining the inner table could be written as

auto inner2 = config->get_table_qualified("first-table.inner");

Arrays of Values

Suppose you had a configuration file like the following:

arr = [1, 2, 3, 4, 5]
mixed-arr = [[1, 2, 3, 4, 5], ["hello", "world"], [0.1, 1.1, 2.1]]

To obtain an array of values, you can do the following:

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

auto vals = config->get_array_of<int64_t>("arr");
// vals is a cpptoml::option<std::vector<int64_t>>

for (const auto& val : *vals)
{
    // val is an int64_t
}

get_array_of will return an option<vector<T>>, which will be empty if the key does not exist, is not of the array type, or contains values that are not of type T.

For nested arrays, it looks like the following:

auto nested = config->get_array_of<cpptoml::array>("mixed-arr");

auto ints = (*nested)[0]->get_array_of<int64_t>();
// ints is a cpptoml::option<std::vector<int64_t>>

auto strings = (*nested)[1]->get_array_of<std::string>();
auto doubles = (*nested)[2]->get_array_of<double>();

There is also a get_qualified_array_of for simplifying arrays located inside nested tables.

Arrays of Tables

Suppose you had a configuration file like the following:

[[table-array]]
key1 = "hello"

[[table-array]]
key1 = "can you hear me"

Arrays of tables are represented as a separate type in cpptoml. They can be obtained like so:

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

auto tarr = config->get_table_array("table-array");

for (const auto& table : *tarr)
{
    // *table is a cpptoml::table
    auto key1 = table->get_as<std::string>("key1");
}

More Examples

You can look at the files files parse.cpp, parse_stdin.cpp, and build_toml.cpp in the root directory for some more examples.

parse_stdin.cpp shows how to use the visitor pattern to traverse an entire cpptoml::table for serialization.

build_toml.cpp shows how to construct a TOML representation in-memory and then serialize it to a stream.

Comments
  • Added write functions that write valid TOML

    Added write functions that write valid TOML

    I created a couple of write functions that given a cpptoml::table will write out valid TOML to a given stream.

    I didn't want to trample on any of the original print() functions yet, so I left those alone.

    I think it looks pretty good.

    I ran clang-format over the changed file so you'll see a couple whitespace changes with this pull request as well. If you want me to remove that I can, but I figured since you have a .clang-format file there that I should use it before sending a pull request.

    opened by dcdillon 19
  • Difficulty in building a TOML document in code

    Difficulty in building a TOML document in code

    There should be some added functions that simplify creating a TOML document in code (and subsequently writing it out).

    Specifically there should be an lvalue version of table::insert() for simple items.

    Additionally, having to create shared pointers for each type and insert them into tables is...cumbersome. There are two ways I can see of fixing this:

    1. Create correct copy constructors for every cpptoml element and creating a version of the insert function that takes const table&, const array&, const value& etc and makes a copy of each.
    2. Creating an element_factory that creates shared pointers to each type.

    (1) is cleaner, but (2) will be more efficient. I don't have a good feeling on which is the right way to go.

    Anyhow, once we hash out a design, I'm happy to add this stuff. Let's discuss.

    opened by dcdillon 8
  • Two possible Date related regressions

    Two possible Date related regressions

    Lovely to see toml 0.5 support. I just carried this over to my RcppTOML but I ran into two regressions, both Date related.

    First, Tom's own example.toml no longer parses. The line

    dob = 1979-05-27T07:32:00-08:00 # First class dates
    

    fails, but passes once the comment is removed:

    dob = 1979-05-27T07:32:00-08:00 
    

    Similarly, I have a file example4.toml and it now falls over

    bla = [ 1979-05-27T07:32:00Z, 1979-05-28T07:32:00Z ] 
    

    but the dates pass individually. The spec is silent about whether arrays of dates are allowed or not, but they worked in the past and I don't see why they should be excluded.

    opened by eddelbuettel 6
  • Please Post New Release

    Please Post New Release

    I am working on adding cpptoml to the Hunter package management system. For that to work well it requires a release version that includes a CMakeLists.txt that includes an install target and CMake package configuration. The latest release package (0.4.0) lacks this, yet I see that HEAD does. Can you make a release for this?

    opened by qbradq 5
  • Getting uint16_t type value problem.

    Getting uint16_t type value problem.

    Hi! I get static_assertion error: .../include/cpptoml.h:301: error: static assertion failed: invalid value type static_assert(valid_value::value, "invalid value type"); ^

    when i try to compile following code:

    auto cfg = cpptoml::parse_file(fname);
    auto conn = cfg->get_table("connection");
    std::string host = *conn->get_as<std::string>("host");
    uint16_t port = *conn->get_as<uint16_t>("port");
    

    What i am doing wrong?

    opened by korst1k 5
  • make_xxx() functions broke Windows build.

    make_xxx() functions broke Windows build.

    Hi, I think the latest make_xxx() function additions broke the windows build. I am getting a couple of errors in the following form in VS 2013.

    Error   1   error C2664: 'std::shared_ptr<cpptoml::value<double>> cpptoml::make_value<double>(T &&)' : cannot convert argument 1 from 'int64_t' to 'double &&'  d:\hog-pom\utils\cpptoml.h  364
    
    opened by barisdemiroz 5
  • Cannot parse nested table arrays

    Cannot parse nested table arrays

    Hi, using

    [services]
    modules = [
        "mdns",
    ]
    
        [services.trigger]
        # Possible options: "udp", "flic"
        mode = "udp"
    
            [services.trigger.udp]
            port = 8875
    
            [services.trigger.flic]
            latency = "NormalLatency"
            uuids = [
                "aa:bb:cc:dd:ee:ff",
                "11:22:33:44:55:66",
            ]
    
    // Works:
    auto services_t = file_conf->get_table("services");
    for (const auto &val : *services_t->get_array_of<std::string>("modules")) {
        services.modules.emplace_back(val); // works
    }
    
    // auto trigger_t = services_t->get_table("trigger");
    // auto flic_t = trigger_t->get_table("flic");
    
    // Doesn't work:
    auto flic_t = file_conf->get_table_qualified("services.trigger.flic");
    for (const auto &val : *flic_t->get_array_of<std::string>("uuids")) {
        services.trigger.flic.uuids.emplace_back(val); // Cannot access memory at address 0x29
    }
    

    Am I missing something?

    opened by skakri 4
  • Regression for parsing floats?

    Regression for parsing floats?

    I fell a little behind updating RcppTOML to the updated cpptoml but just did so. It turns out that I no longer pass all the regression tests I have, in particular I now fail to parse this line with

    key2 = 1e1_000
    

    at least on my teeny i386 laptop.

    Could this be related to this commit of yours ?

    opened by eddelbuettel 4
  • issue handling numeric properties

    issue handling numeric properties

    ex:

    some_property = 500.0 // value->as() fine some_property = 500 // value->as() results in crash

    while this is correct in toml spec, it puts the onus of type correctness on the toml file creator, which IMO, seems to ask too much of them. perhaps value->as() & value->as<int64_t>() should work for both integer and float property types?

    opened by gordonmcshane 4
  • added biicode support

    added biicode support

    Hi skystrife,

    I just added biicode support for your library and explained basics in the readme , it's a biicode.conf file and some unobtrusive changes in CMakeLists.txt

    To try it out with biicode (once installed):

     $ git clone https://github.com/MariadeAnton/cpptoml
     $ cd cpptoml
     $ bii init -L
     $ bii build
    

    I've published cpptoml in biicode amalulla/cpptoml, but would be great if you could register keep it up-to-date in biicode.

    Hope you like this,

    Maria

    opened by MariadeAnton 4
  • Fix find_end_of_date to actually find the end of date (was eating all…

    Fix find_end_of_date to actually find the end of date (was eating all…

    … the whitespace behind a date to comment and failing)

    E.g. date = 1990-01-01 # some comment da = 1200-01-01T00:00:00Z # some ohther comment (plain whitespace suffices to fail too)

    opened by monkeydom 3
  • GCC 11.1.0 build errors

    GCC 11.1.0 build errors

    https://invent.kde.org/-/snippets/1655

    Errors of interest are:

    /tmp/makepkg/decaf-emu-git/src/decaf-emu/libraries/cpptoml/include/cpptoml.h:1033:52: error: ‘numeric_limits’ is not a member of ‘std’
     1033 |         if (static_cast<uint64_t>(v->get()) > std::numeric_limits<T>::max())
          |                                                    ^~~~~~~~~~~~~~
    /tmp/makepkg/decaf-emu-git/src/decaf-emu/libraries/cpptoml/include/cpptoml.h:1033:68: error: expected primary-expression before ‘>’ token
     1033 |         if (static_cast<uint64_t>(v->get()) > std::numeric_limits<T>::max())
          |                                                                    ^
    /tmp/makepkg/decaf-emu-git/src/decaf-emu/libraries/cpptoml/include/cpptoml.h:1033:71: error: ‘::max’ has not been declared; did you mean ‘std::max’?
     1033 |         if (static_cast<uint64_t>(v->get()) > std::numeric_limits<T>::max())
          |                                                                       ^~~
          |                                                                       std::max
    
    opened by Valmar33 2
  • Conan Support

    Conan Support

    Please, pretty please, add conan support for this great library! It is the last remaining dependency (out of 7) in our project that is not available on Conan Center. For inspiration, one can look at this project: https://github.com/jgsogo/conan-cpptoml.

    Thanks!

    opened by gegles 0
  • cmake: output cpptoml.pc for pkg-config discoverability

    cmake: output cpptoml.pc for pkg-config discoverability

    I'm packaging wireplumber for NixOS (nixpkgs), and it uses this library. With this change, meson is able to just discover cpptoml via typical pkg-config mechanisms. I'm going to carry this patch for now.

    Thanks!

    opened by colemickens 0
  • g++-11 requires limits header

    g++-11 requires limits header

    The CRAN maintainers, who tend to be very proactive with new compiler builds, alerted me that my RcppROML package was failing builds under g++-11, and hinted that the change was a one-liner.

    I have now confirmed this (in an Ubuntu 21.04 container with g++-11 from this launchpad repo. I will try to bundle this up in a new container too later in the week.

    opened by eddelbuettel 9
Releases(v0.1.1)
  • v0.1.1(Oct 22, 2018)

    Bugfixes:

    • Fix find_end_of_date not working with trailing comments or arrays of dates (@monkeydom)
    • Allow empty inline tables (@monkeydom)
    • Fix potentially dangling reference in option::value_or (thanks @antonte for the report)
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Oct 22, 2018)

Owner
Chase Geigle
Chase Geigle
Header-only TOML config file parser and serializer for C++17 (and later!).

toml++ homepage ✨ This README is fine, but the toml++ homepage is better. ✨ Library features Header-only Supports the latest TOML release (v1.0.0), pl

Mark Gillard 970 Jan 9, 2023
A C++11 or library for parsing and serializing JSON to and from a DOM container in memory.

Branch master develop Azure Docs Drone Matrix Fuzzing --- Appveyor codecov.io Boost.JSON Overview Boost.JSON is a portable C++ library which provides

Boost.org 333 Dec 29, 2022
Header-only C++11 library to encode/decode base64, base64url, base32, base32hex and hex (a.k.a. base16) as specified in RFC 4648, plus Crockford's base32. MIT licensed with consistent, flexible API.

cppcodec Header-only C++11 library to encode/decode base64, base64url, base32, base32hex and hex (a.k.a. base16) as specified in RFC 4648, plus Crockf

Topology 491 Dec 28, 2022
Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications

Zmeya Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications. Zmeya is not even a serializ

Sergey Makeev 99 Dec 24, 2022
Header-only library for automatic (de)serialization of C++ types to/from JSON.

fuser 1-file header-only library for automatic (de)serialization of C++ types to/from JSON. how it works The library has a predefined set of (de)seria

null 51 Dec 17, 2022
libcluon is a small and efficient, single-file and header-only library written in modern C++ to power microservices.

libcluon Linux & OSX Build (TravisCI) Win64 Build (AppVeyor) Test Coverage Coverity Analysis CII Best Practices libcluon is a small single-file, heade

Christian Berger 81 Nov 30, 2022
Parsing gigabytes of JSON per second

simdjson : Parsing gigabytes of JSON per second JSON is everywhere on the Internet. Servers spend a *lot* of time parsing it. We need a fresh approach

null 16.3k Jan 2, 2023
Use to copy a file from an NTFS partitioned volume by reading the raw volume and parsing the NTFS structures.

ntfsDump Use to copy a file from an NTFS partitioned volume by reading the raw volume and parsing the NTFS structures. Similar to https://github.com/P

null 102 Dec 30, 2022
Your binary serialization library

Bitsery Header only C++ binary serialization library. It is designed around the networking requirements for real-time data delivery, especially for ga

Mindaugas Vinkelis 771 Jan 2, 2023
Cap'n Proto serialization/RPC system - core tools and C++ library

Cap'n Proto is an insanely fast data interchange format and capability-based RPC system. Think JSON, except binary. Or think Protocol Buffers, except

Cap'n Proto 9.5k Jan 1, 2023
A C++11 library for serialization

cereal - A C++11 library for serialization cereal is a header-only C++11 serialization library. cereal takes arbitrary data types and reversibly turns

iLab @ USC 3.4k Jan 3, 2023
FlatBuffers: Memory Efficient Serialization Library

FlatBuffers FlatBuffers is a cross platform serialization library architected for maximum memory efficiency. It allows you to directly access serializ

Google 19.7k Jan 9, 2023
FlatBuffers Compiler and Library in C for C

OS-X & Ubuntu: Windows: The JSON parser may change the interface for parsing union vectors in a future release which requires code generation to match

null 550 Dec 25, 2022
Simple C++ 20 Serialization Library that works out of the box with aggregate types!

BinaryLove3 Simple C++ 20 Serialization Library that works out of the box with aggregate types! Requirements BinaryLove3 is a c++20 only library.

RedSkittleFox 14 Sep 2, 2022
A C++ library for interacting with JSON.

JsonCpp JSON is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value p

null 6.9k Jan 4, 2023
CppSerdes is a serialization/deserialization library designed with embedded systems in mind

A C++ serialization/deserialization library designed with embedded systems in mind

Darren V Levine 79 Nov 5, 2022
Morse code decoding library

ggmorse Morse code decoding library ggmorse2.mp4 ggmorse0.mp4 ggmorse1.mp4 Try it out You can easily test the library using the free GGMorse applicati

Georgi Gerganov 106 Dec 23, 2022
C++17 library for all your binary de-/serialization needs

blobify blobify is a header-only C++17 library to handle binary de-/serialization in your project. Given a user-defined C++ struct, blobify can encode

Tony Wasserka 247 Dec 8, 2022
C++ BSON Library

This is a standalone BSON ("binary JSON") library for C++. (See bsonspec.org for more information on the BSON format.) The library is at this time a b

Dwight Merriman 57 Dec 16, 2022