toml++

repository·master·Indexed 24 days ago

https://github.com/marzer/tomlplusplus

A C++17 TOML parser and serializer supporting the TOML v1.0.0 specification. It features a single-header or regular library mode, support for C++ modules, and serialization to TOML, JSON, and YAML. Key functionality includes parsing files and strings via toml::parse_file and toml::parse, data manipulation using node_view, and customizable behavior through preprocessor defines.

Tokens
6K
Snippets
12
Records
16
Agent score
82%

What's inside tomlplusplus

  1. Manipulate TOML data with node_view

    master

    TOML data is represented as a tree of toml::value, toml::array, and toml::table (all inheriting from toml::node). You can access elements using operator[] or at_path(), which return a toml::node_view.

    Common operations include:

    • Querying values: Use .value<T>() to get an std::optional<T> or .value_or(default) for a fallback.
    • Accessing references: Use .ref<T>() for a direct reference (use with caution).
    • Chaining: tbl["key1"]["key2"] allows deep querying.
    • Arrays: Use .as_array() to get a pointer to the underlying toml::array for iteration (for_each) or modification (push_back).
    #include <iostream>
    #include <toml++/toml.hpp>
    using namespace std::string_view_literals;
    
    int main()
    {
        static constexpr auto source = R"(
            str = "hello world"
    
            numbers = [ 1, 2, 3, "four", 5.0 ]
            vegetables = [ "tomato", "onion", "mushroom", "lettuce" ]
            minerals = [ "quartz", "iron", "copper", "diamond" ]
    
            [animals]
            cats = [ "tiger", "lion", "puma" ]
            birds = [ "macaw", "pigeon", "canary" ]
            fish = [ "salmon", "trout", "carp" ]
        )"sv;
        toml::table tbl = toml::parse(source);
    
        // different ways of directly querying data
        std::optional<std::string_view> str1 = tbl["str"].value<std::string_view>();
        std::optional<std::string>      str2 = tbl["str"].value<std::string>();
        std::string_view                str3 = tbl["str"].value_or(""sv);
        std::string&                    str4 = tbl["str"].ref<std::string>(); // ~~dangerous~~
    
        std::cout << *str1 << "\n";
        std::cout << *str2 << "\n";
        std::cout << str3 << "\n";
        std::cout << str4 << "\n";
    
        // get a toml::node_view of the element 'numbers' using operator[]
        auto numbers = tbl["numbers"];
        std::cout << "table has 'numbers': " << !!numbers << "\n";
        std::cout << "numbers is an: " << numbers.type() << "\n";
        std::cout << "numbers: " << numbers << "\n";
    
        // get the underlying array object to do some more advanced stuff
        if (toml::array* arr = numbers.as_array())
        {
            // visitation with for_each() helps deal with heterogeneous data
            arr->for_each([](auto&& el)
            {
                if constexpr (toml::is_number<decltype(el)>)
                    (*el)++;
                else if constexpr (toml::is_string<decltype(el)>)
                    el = "five"sv;
            });
    
            // arrays are very similar to std::vector
            arr->push_back(7);
            arr->emplace_back<toml::array>(8, 9);
            std::cout << "numbers: " << numbers << "\n";
        }
    
        // node-views can be chained to quickly query deeper
        std::cout << "cats: " << tbl["animals"]["cats"] << "\n";
        std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n";
    
        // can also be retrieved via absolute path
        std::cout << "cats: " << tbl.at_path("animals.cats") << "\n";
        std::cout << "fish[1]: " << tbl.at_path("animals.fish[1]") << "\n";
    
        // ...even if the element doesn't exist
        std::cout << "dinosaurs: " << tbl["animals"]["dinosaurs"] << "\n"; //no dinosaurs :(
    
        return 0;
    }
  2. Enable unreleased TOML language features

    master

    By default, toml++ supports the latest stable TOML release (v1.0.0). To enable experimental support for unreleased features (such as hex floating-point values, + in key names, or new escape sequences), define the following macro before including the library:

    #define TOML_ENABLE_UNRELEASED_FEATURES 1
    #include <toml++/toml.hpp>
  3. Install toml++ via various package managers

    master

    toml++ can be integrated into your project using several methods:

    Single-header (Easiest)

    1. Download toml.hpp and place it in your source tree.

    Regular flavour (Git/Manual)

    1. Clone the repository.
    2. Add tomlplusplus/include to your include paths.
    3. (Optional) For module support, add tomlplusplus/modules and enable TOMLPLUSPLUS_BUILD_MODULES.

    Package Managers

    • Conan: Add tomlplusplus/3.4.0 to your conanfile.
    • DDS: Add tomlpp^3.4.0 to your package.json5.
    • Meson: Run meson wrap install tomlplusplus.
    • Vcpkg: Run vcpkg install tomlplusplus.
    • CMake: Use FetchContent.
    • Git Submodules: git submodule add --depth 1 https://github.com/marzer/tomlplusplus.git tomlplusplus.

    Python

    Use the pytomlpp wrapper for high-performance TOML parsing in Python: pip install pytomlpp

    // CMake FetchContent
    include(FetchContent)
    FetchContent_Declare(
        tomlplusplus
        GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
        GIT_TAG v3.4.0
    )
    FetchContent_MakeAvailable(tomlplusplus)
    
    // Meson
    meson wrap install tomlplusplus
    tomlplusplus_dep = dependency('tomlplusplus')
    
    // Git Submodule
    git submodule add --depth 1 https://github.com/marzer/tomlplusplus.git tomlplusplus
    
    // Python
    pip install pytomlpp
  4. Speed up compilation of toml++

    master

    Since toml++ is a large header-only library, it can increase compilation times. You can optimize this using two methods:

    1. Disable header-only mode:

      • Set #define TOML_HEADER_ONLY 0 in a global header included by your project.
      • In exactly one translation unit, define #define TOML_IMPLEMENTATION before including the library.
    2. Disable unused features:

      • If you only need serialization and not parsing, set #define TOML_ENABLE_PARSER 0 to avoid compiling the parser code.
    // global_header_that_includes_toml++.h
    
    #define TOML_HEADER_ONLY 0
    #include <toml.hpp>
    
    // ---
    
    // some_code_file.cpp
    
    #define TOML_IMPLEMENTATION
    #include "global_header_that_includes_toml++.hpp"
  5. Install toml++ using package managers

    master

    Depending on your build system, use one of the following methods:

    Conan Add tomlplusplus/3.4.0 to your conanfile.

    DDS Add tomlpp to your package.json5:

    depends: [
        'tomlpp^3.4.0',
    ]

    Tipi.build Add the following to your .tipi/deps:

    {
    	"marzer/tomlplusplus": {}
    }

    Vcpkg

    vcpkg install tomlplusplus

    Meson

    meson wrap install tomlplusplus

    Then use in meson.build:

    tomlplusplus_dep = dependency('tomlplusplus')

    CMake (FetchContent)

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

    Git Submodule

    git submodule add --depth 1 https://github.com/marzer/tomlplusplus.git tomlplusplus
  6. Handle parsing errors without exceptions

    master

    If your project cannot use exceptions, you can disable them by setting #define TOML_EXCEPTIONS 0 before including the library. In this mode, parsing functions return a toml::parse_result instead of a toml::table. You can check for success using the boolean operator and retrieve the table via .table() or the error via .error().

    #include <iostream>
    
    #define TOML_EXCEPTIONS 0 // only necessary if you've left them enabled in your compiler
    #include <toml++/toml.hpp>
    
    int main()
    {
        toml::parse_result result = toml::parse_file("configuration.toml");
    
        if (!result)
        {
            std::cerr << "Parsing failed:\n" << result.error() << "\n";
            return 1;
        }
    
        do_stuff_with_your_config(std::move(result).table()); // 'steal' the table from the result
        return 0;
    }
  7. Build and run toml-test tools on Windows (Visual Studio)

    master

    To build the encoder and decoder on Windows:

    1. Open toml++.sln in Visual Studio.
    2. Build the two projects located in the toml-test solution folder.
    3. The binaries will be compiled into a target-specific subfolder under /bin in the repository root.
    4. Run toml-test against the generated executables:
    toml-test ./bin/win64_vc143_Release_Application/tt_decoder.exe
    toml-test ./bin/win64_vc143_Release_Application/tt_encoder.exe --encoder
    toml-test ./bin/win64_vc143_Release_Application/tt_decoder.exe
    toml-test ./bin/win64_vc143_Release_Application/tt_encoder.exe --encoder
  8. Build and run toml-test tools on Linux (and WSL)

    master

    To build and run the tools on Linux or WSL using Meson and Ninja:

    1. Initialize the build directory (first time only):
    meson build_tt --buildtype=release -Dbuild_tt=true -Dgenerate_cmake_config=false

    Note: Pass -Duse_vendored_libs=false to meson if you want to use the system-installed version of nlohmann/json instead of the vendored one.

    1. Build and run:
    cd build_tt
    ninja && toml-test ./toml-test/tt_decoder && toml-test ./toml-test/tt_encoder --encoder
    meson build_tt --buildtype=release -Dbuild_tt=true -Dgenerate_cmake_config=false
    
    cd build_tt
    ninja && toml-test ./toml-test/tt_decoder && toml-test ./toml-test/tt_encoder --encoder
  9. Install toml++ via Single-header or Regular flavour

    master

    toml++ can be integrated into your project in two ways:

    Single-header flavour

    Best for quick integration without build system changes.

    1. Drop toml.hpp anywhere in your source tree.
    2. Include it in your code.

    Regular flavour

    Best for larger projects or when using C++ modules.

    1. Clone the repository.
    2. Add tomlplusplus/include to your include paths.
    3. (Optional) For module support, add tomlplusplus/modules to your include paths and enable the TOMLPLUSPLUS_BUILD_MODULES preprocessor definition.
    4. Use #include <toml++/toml.hpp> or import tomlplusplus;.
  10. Set up the toml-test encoder and decoder

    master

    This guide describes how to build and run the encoder and decoder tools used for testing with the toml-test suite.

    Note: This is specifically for testing compatibility with the toml-test suite and is distinct from running the toml++ library's own unit tests.

    Prerequisites

    1. Compile the toml-test runner following its own installation instructions.
    2. Ensure toml-test is in your system PATH or available as an alias.
    3. Linux only: Install ninja and meson:
    sudo apt update && sudo apt install -y python3 python3-pip ninja-build
    sudo pip3 install meson

    All commands assume you are in the toml++ repository root.

    sudo apt update && sudo apt install -y python3 python3-pip ninja-build
    sudo pip3 install meson
  11. Configure toml++ via preprocessor defines

    master

    You can customize toml++ behavior using preprocessor #defines. These must be set before including the library. Note that some options have ABI implications; the library uses inline namespaces to prevent incompatible linking.

    OptionTypeDescriptionDefault
    TOML_ASSERT(expr)function macroSets the assert function used by the library.assert()
    TOML_CALLCONVdefineCalling convention for exported functions.undefined
    TOML_CONFIG_HEADERstring literalIncludes a header file before the library.undefined
    TOML_DISABLE_CONDITIONAL_NOEXCEPT_LAMBDAbooleanNeeded for MSVC's legacy lambda processor.0
    TOML_ENABLE_FORMATTERSbooleanEnables JSON/YAML formatters. Set to 0 to reduce binary size/compile time.1
    TOML_ENABLE_FLOAT16booleanEnables _Float16 support.per compiler
    TOML_ENABLE_PARSERbooleanEnables the parser. Set to 0 to reduce binary size/compile time.1
    TOML_ENABLE_UNRELEASED_FEATURESbooleanEnables support for unreleased TOML features.0
    TOML_ENABLE_WINDOWS_COMPATbooleanEnables transparent wide/narrow string conversion on Windows.1 on Windows
    TOML_EXCEPTIONSbooleanSets whether the library uses exceptions.per compiler
    TOML_HEADER_ONLYbooleanDisable to explicitly control implementation compilation.1
    TOML_IMPLEMENTATIONdefineEnable implementation compilation when TOML_HEADER_ONLY is 0.undefined
    TOML_OPTIONAL_TYPEtype nameOverrides std::optional<T> with a custom type.undefined
    TOML_SMALL_FLOAT_TYPEtype nameCustom 'small float' type (e.g. half-precision).undefined
    TOML_SMALL_INT_TYPEtype nameCustom 'small integer' type.undefined
  12. Basic usage of toml++

    master

    toml++ allows you to parse TOML files, manipulate data, and re-serialize it into TOML, JSON, or YAML formats.

    Key operations include:

    • Parsing: Use toml::parse_file to load a file into a configuration object.
    • Accessing Data: Use the [] operator to navigate keys and .value_or(default) to safely retrieve values with a fallback.
    • Modifying Data: Use insert_or_assign to add or update keys.
    • Iteration: Use for_each with a visitor pattern or a ranged-for loop for (auto&& [k, v] : config) to traverse data.
    • Serialization: Use std::cout << config for TOML, or use toml::json_formatter{ config } and toml::yaml_formatter{ config } for other formats.
    #include <toml++/toml.hpp>
    
    using namespace std::literals;
    
    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";