toml11は、C++11,14,17,20のための豊富な機能を持つTOML言語ライブラリです。
- TOML言語の最新規格に準拠しています。
- TOML言語標準のテストケースすべてにパスしています。
- TOML言語の次期バージョン (v1.1.0) にマージされた新機能のそれぞれを試すことができます。
- エラーが起きた位置を含めたわかりやすいエラーメッセージを出力します。
- コメントもパースし、対応する値に保存します。
- 16進整数やクオートの種類などのフォーマット情報を保持し、シリアライズ時に考慮します。
- 例外を投げないバージョンをサポートします。
- TOML値からの複雑な型変換をサポートします。
- 整数、浮動小数点数、コンテナ等の型を変更可能です。
- TOML言語にない一部の拡張機能を試すことができます。
#include <toml.hpp>
#include <iostream>
// ```toml
// title = "an example toml file"
// nums = [3, 1, 4, 1, 5] # pi!
// ```
int main()
{
// select TOML version at runtime (optional)
auto data = toml::parse("example.toml", toml::spec::v(1,1,0));
// find a value with the specified type from a table
std::string title = toml::find<std::string>(data, "title");
// convert the whole array into STL-like container automatically
std::vector<int> nums = toml::find<std::vector<int>>(data, "nums");
// access with STL-like manner
if( ! data.contains("foo"))
{
data["foo"] = "bar";
}
if(data.at("nums").is_array())
{
data.push_back(9);
}
// check comments
assert(data.at("nums").comments().at(0) == "# pi!");
// pass a fallback
std::string name = toml::find_or<std::string>(data, "name", "not found");
// serialization considering format info
data.at("nums").as_array_fmt().fmt = toml::array_format::multiline;
data.at("nums").as_array_fmt().indent_type = toml::indent_char::space;
data.at("nums").as_array_fmt().body_indent = 2;
std::cout << toml::format(data) << std::endl;
return 0;
}
詳細な機能とリファレンスに関しては、ドキュメントを参照してください。
toml11を使うには複数の方法があります。
ここではそれぞれを短く紹介します。詳細は、ドキュメントを参照してください。
single_include/toml.hpp
を好きなところにコピーして、インクルードパスを通してください。
git submoduleなどでサブディレクトリにすれば、toml11/include
にインクルードパスを通すか、
add_subdirectory(toml11)
とすることで使用できます。
CMakeの FetchContent
を使用することで、build
ディレクトリに自動でダウンロードすることができます。
include(FetchContent)
FetchContent_Declare(
toml11
GIT_REPOSITORY https://github.com/ToruNiina/toml11.git
GIT_TAG v4.0.3
)
FetchContent_MakeAvailable(toml11)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE toml11::toml11)
CMake package managerを導入すると、以下のようにして使用することができます。
include(cmake/CPM.cmake)
CPMAddPackage("gh:ToruNiina/toml11@4.1.0")
add_executable(main main.cpp)
target_link_libraries(main PUBLIC toml11::toml11)
以下の手順で、CMakeを使ってインストールすることができます。
$ git clone https://github.com/ToruNiina/toml11
$ cd toml11
$ git submodule update --init --recursive
$ cmake -B ./build/
$ cmake --build ./build/
$ cmake --install ./build --prefix /path/to/toml11
-DTOML11_PRECOMPILE=ON
とすることで、ライブラリの一部の関数をコンパイルできます。
この場合、C++バージョンによって使用できる標準ライブラリ機能が変化し、
インターフェースの一部が変わるため、CMAKE_CXX_STANDARD
を指定する必要があります。
$ cmake -B ./build/ -DTOML11_PRECOMPILE=ON -DCMAKE_CXX_STANDARD=11/14/17/20
$ cmake --build ./build/
ライブラリをリンクする場合は、CMakeで
target_link_libraries(your_target PUBLIC toml11::toml11)
とするか、コンパイラに-DTOML11_COMPILE_SOURCES
を渡してください。
-DTOML11_BUILD_EXAMPLES=ON
とすることで、examples/
をコンパイルできます。
$ cmake -B ./build/ -DTOML11_BUILD_EXAMPLES=ON
$ cmake --build ./build/
-DTOML11_BUILD_TESTS=ON
とすることで、ユニットテストをコンパイルできます。
また、-DTOML11_BUILD_TOML_TESTS=ON
とすることで、toml-test用のencoder
とdecoder
をコンパイルできます。
$ cmake -B ./build/ -DTOML11_BUILD_EXAMPLES=ON
$ cmake --build ./build/
ここでは、toml11の持つ機能を短く紹介します。
詳細についてはドキュメントを参照してください。
ファイルをパースする場合は、toml::parse
を使います。
ファイル全体の型は常にテーブルですが、 toml::value
はコメントや
フォーマット情報などのメタデータを持つので、toml::parse
からは
toml::table
ではなく toml::value
が返ります。
const toml::value input = toml::parse("input.toml");
文字列そのものをパースする場合は、toml::parse_str
を使います。
const toml::value input = toml::parse_str("a = 42");
文字列リテラルをパースする際は、""_toml
リテラルを使うことができます。
using namespace toml::literals::toml_literals;
const toml::value lit = "a = 42"_toml;
toml::parse
やparse_str
は文法エラーの際に toml::syntax_error
例外を投げます。
what()
で得られるエラーメッセージは以下のようになります。
[error] bad integer: `_` must be surrounded by digits
--> internal string at line 64 in file main.cpp
|
1 | a = 123__456
| ^-- invalid underscore
Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755
Hint: invalid: _42, 1__000, 0123
エラーメッセージにはtoml::color::enable()
を呼ぶことで色を付けることも可能です。
toml::try_parse
を使うことで、例外を投げずに toml::result<toml::value, std::vector<toml::error_info>>
を受け取ることができます。
const auto input = toml::try_parse("input.toml");
if(input.is_ok())
{
std::cout << input.unwrap().at("a").as_integer() << std::endl;
}
また、使用するTOML言語のバージョンを簡単に、かつ細かく変更できるようになりました。
TOML v1.0.0に加えて、v1.1.0の新機能を一部だけ使用するというような制御が可能です。
toml::spec s = toml::spec::v(1, 0, 0);
s.v1_1_0_allow_trailing_comma_in_inline_tables = true;
const toml::value input = toml::parse("input.toml");
また、TOML言語自体に含まれない言語拡張もいくつか用意しています。
toml::spec s = toml::spec::v(1, 0, 0);
s.ext_hex_float = true; // 16進数浮動小数点数を許可
s.ext_null_value = true; // 空の値 `null` を許可
s.ext_num_suffix = true; // `100_msec`などのsuffixを許可
各機能の紹介とリファレンスは、ドキュメントを参照してください。
toml::value
はアクセス用のメンバ関数、at()
や is_xxx()
, as_xxx()
を持ちます。
const toml::value input = toml::parse("input.toml");
if(input.contains("a") && input.at("a").is_integer())
{
std::cout << input.at("a").as_integer() << std::endl;
}
toml::find
を使うことで、型変換と検索を同時に行うことができます。
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<std::string>(input, "a") << std::endl;
型変換や値の検索に失敗した場合は、toml::type_error
が送出されます。
その場合のエラーメッセージは以下のようになります。
[error] toml::value::as_string(): bad_cast to string
--> input.toml
|
1 | a = 123_456
| ^^^^^^^-- the actual type is integer
ネストされたテーブルやテーブルの配列にも同じ方法でアクセスできます。
// [a]
// b = [
// {c = 42},
// {c = 54}
// ]
const toml::value input = toml::parse("input.toml");
std::cout << toml::find<int>(input, "a", "b", 1, "c") << std::endl;
ほとんどのSTLコンテナや、同様のインターフェースを持つコンテナへ変換が可能です。
// array = [3,1,4,1,5]
const toml::value input = toml::parse("input.toml");
const auto a1 = toml::find<std::vector<int> >(input, "array") << std::endl;
const auto a2 = toml::find<std::array<int, 5>>(input, "array") << std::endl;
const auto a3 = toml::find<std::deque<int> >(input, "array") << std::endl;
const auto a4 = toml::find<boost::container::small_vector<int, 8>>(input, "array") << std::endl;
また、複雑なTOML値に対して、高度な型変換を行うことができます。
mixed_array = [
42,
3.14,
{a = "foo", b = "bar"}
]
const toml::value input = toml::parse("input.toml");
const auto mixed = toml::find<
std::tuple<int, double, std::map<std::string, std::string>>
>(input, "mixed_array") << std::endl;
マクロの使用または特定の関数を定義することで、ユーザー定義型にも変換が可能です。
namespace extlib
{
struct foo
{
int a;
std::string b;
};
} // extlib
TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(extlib::foo, a, b)
// ...
const auto input = R"(
[foo]
a = 42
b = "bar"
)"_toml;
const extlib::foo f = toml::find<extlib::foo>(input, "foo");
toml::find_or
を使うことで、失敗時にデフォルト値を得ることができます。
const toml::value input = toml::parse("input.toml");
std::cout << toml::find_or(input, "a", 6*9) << std::endl;
詳細についてはドキュメントを参照してください。
toml11は、値に関するコメントを値に保存します。
値に関するコメントとは、ある値の直前に書かれた一連のコメントと、値の直後に改行を挟まず書かれたコメントです。
# これは a のコメントです。
# これも a のコメントです。
a = 42 # これも a のコメントです。
# これは改行で分かれているので、 b のコメントではありません。
# これは b のコメントです。
b = "foo"
これは std::vector<std::string>
と同じインターフェースで toml::value
に格納されます。
const toml::value input = toml::parse("input.toml");
std::cout << input.at("a").comments().size() << std::endl;
std::cout << input.at("a").comments().at(0) << std::endl;
詳細についてはドキュメントを参照してください。
toml11の目標の一つは、わかりやすいエラーメッセージを出力することです。
パースエラーに対しては以下のようなエラーメッセージが、
[error] bad integer: `_` must be surrounded by digits
--> internal string at line 64 in file main.cpp
|
1 | a = 123__456
| ^-- invalid underscore
Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755
Hint: invalid: _42, 1__000, 0123
実際に格納されている型と異なる型を要求した場合には以下のようなエラーメッセージが表示されます。
[error] toml::value::as_string(): bad_cast to string
--> input.toml
|
1 | a = 123_456
| ^^^^^^^-- the actual type is integer
このようなエラーメッセージを、TOMLの文法とは関係のないユーザー特有の処理に対しても出力することが可能です。
const toml::value& a = input.at("a");
if(a.as_integer() < 0)
{
const toml::error_info err = toml::make_error_info(
"positive integer is required",
a, "but got negative value"
);
std::cerr << toml::format_error(err) << std::endl;
}
詳細はドキュメントを参照してください。
toml::format
を使うことで、toml::value
を std::string
にフォーマットできます。
const toml::value input = toml::parse("input.toml");
std::cout << toml::format(input) << std::endl;
toml::format
はフォーマット情報を参照します。
なので、フォーマット方法を変更することが可能です。
toml::value output(toml::table{ {"a", 0xDEADBEEF} });
output.at("a").as_integer_fmt().fmt = toml::integer_format::hex;
output.at("a").as_integer_fmt().spacer = 4;
std::cout << toml::format(output) << std::endl;
// a = 0xdead_beef
テーブルや配列のフォーマットも指定が可能です。
toml::value output(toml::table{
{"array-of-tables", toml::array{}},
{"subtable", toml::table{}},
});
auto& aot = output.at("array-of-tables");
aot.as_array_fmt().fmt = toml::array_format::multiline;
aot.as_array_fmt().body_indent = 4;
aot.as_array_fmt().closing_indent = 2;
toml::value v1(toml::table{ {"a", 42}, {"b", 3.14} });
v1.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v1));
toml::value v2(toml::table{ {"a", 42}, {"b", 3.14} });
v2.as_table_fmt().fmt = toml::table_format::oneline;
aot.push_back(std::move(v2));
output.at("subtable").as_table_fmt().fmt = toml::table_format::dotted;
output.at("subtable")["a"] = 42;
output.at("subtable")["b"] = 3.14;
std::cout << toml::format(output) << std::endl;
// subtable.b = 3.14
// subtable.a = 42
// array-of-tables = [
// {b = 3.14, a = 42},
// {b = 2.71, a = 54},
// ]
これらの設定はパース時に読み取られ、値を変更した際も型が変わらない限り維持されます。
どのような指定が可能かなどの詳細はドキュメントを参照してください。
toml::value
が持つ型の多く、integer_type
やarray_type
などはtype_config
型を変更することで変更可能です。
examples
ディレクトリには、
多倍長整数を使用する場合やコンテナを変更する場合、ユニコードを正規化する場合などの複雑な使用例を用意しています。
そのような状況での実装例として参照してください。
examples
ディレクトリでは、
型の設定の他にも実装例を紹介しています。
- boost_container
array_type
やtable_type
にboost::container
のコンテナを使う例です。
- boost_multiprecision
integer_type
やfloating_type
にboost::multiprecision
の多倍長数値型を使う例です。
- parse_file
- 少し複雑な場合も含めた、型変換の実装例です。対応するTOMLファイルが同梱されています。
- reflect
- boost-ext/reflectを用いたユーザー定義型との自型変換の例です。
- unicode
- uni-algoを用いて、キーを検索する際にユニコード文字列を正規化する例です。
toml11 v3からは複数の破壊的変更が追加されています。
シンプルな使い方をしている場合にはほとんど変更せずに済むように努力はしていますが、 高度な機能を利用していた場合は多少の変更が必要になります。
しかし、追加された機能や整理された機能は、その分の利便性を提供できると考えています。
- ブランチを
master
からmain
に変更 toml::basic_value
のtemplate
引数を変更- フォーマット情報を陽に格納するため
toml::string
を廃止 - フォーマット情報を使用するため
toml::format
の引数を変更 - TOMLバージョン情報を格納する
toml::spec
を追加するためtoml::parse
のデフォルト引数を変更 toml::source_location
のインターフェースを複数行を前提とした形に変更toml::format_error
の引数を変更toml::format_underline
の名称をtoml::format_location
に変更toml::color
の制御方法をtoml::color::enable()
に統一
toml::parse_str
の追加toml::try_parse
の追加- バイト列のパースをサポート
toml::value
にフォーマット情報を追加- コメントをデフォルトで保存するよう変更
single_include/toml.hpp
の追加- コンパイル済みライブラリとしての使用を可能に
このライブラリに新機能を追加、あるいはバグを修正してくださったコントリビュータの方々に感謝します。
- Guillaume Fraux (@Luthaf)
- Windows support and CI on Appvayor
- Intel Compiler support
- Quentin Khan (@xaxousis)
- Found & Fixed a bug around ODR
- Improved error messages for invalid keys to show the location where the parser fails
- Petr Beneš (@wbenny)
- Fixed warnings on MSVC
- Ivan Shynkarenka (@chronoxor)
- Fixed Visual Studio 2019 warnings
- Fix compilation error in
<filesystem>
with MinGW
- Khoi Dinh Trinh (@khoitd1997)
- Fixed warnings while type conversion
- @KerstinKeller
- Added installation script to CMake
- J.C. Moyer (@jcmoyer)
- Fixed an example code in the documentation
- Jt Freeman (@blockparty-sh)
- Fixed feature test macro around
localtime_s
- Suppress warnings in Debug mode
- Fixed feature test macro around
- OGAWA Kenichi (@kenichiice)
- Suppress warnings on intel compiler
- Fix include path in README
- Jordan Williams (@jwillikers)
- Fixed clang range-loop-analysis warnings
- Fixed feature test macro to suppress -Wundef
- Use cache variables in CMakeLists.txt
- Automate test set fetching, update and refactor CMakeLists.txt
- Scott McCaskill
- Parse 9 digits (nanoseconds) of fractional seconds in a
local_time
- Parse 9 digits (nanoseconds) of fractional seconds in a
- Shu Wang (@halfelf)
- fix "Finding a value in an array" example in README
- @maass-tv and @SeverinLeonhardt
- Fix MSVC warning C4866
- Mohammed Alyousef (@MoAlyousef)
- Made testing optional in CMake
- Alex Merry (@amerry)
- Add missing include files
- sneakypete81 (@sneakypete81)
- Fix typo in error message
- Oliver Kahrmann (@founderio)
- Fix missing filename in error message if parsed file is empty
- Karl Nilsson (@karl-nilsson)
- Fix many spelling errors
- ohdarling88 (@ohdarling)
- Fix a bug in a constructor of serializer
- estshorter (@estshorter)
- Fix MSVC warning C26478
- Philip Top (@phlptp)
- Improve checking standard library feature availability check
- Louis Marascio (@marascio)
- Fix free-nonheap-object warning
- Axel Huebl (@ax3l)
- Make installation optional if the library is embedded
- Ken Matsui (@ken-matsui)
- Support user-defined error message prefix
- Support dynamic color mode
- Giel van Schijndel (@muggenhor)
- Remove needless copy in
parse
function
- Remove needless copy in
- Lukáš Hrázký (@lukash)
- Add a
parse(FILE *)
interface and improve file-related error messages
- Add a
- spiderman idog (@spiderman-idog)
- Fix typo in README
- Jajauma's GitHub (@Jajauma)
- Avoid possible lexer truncation warnings
- Moritz Klammler (@ctcmkl)
- Many patches in (#200) including:
- Improve CMake scripts, build process, and test file handling
- Detect error when
discard_comments
is accessed - And more.
- Chris White (@cxw42)
- Fix address-sanitizer error when parsing literal strings having invalid UTF-8 characters
- Fix function name in error messages
- offa (@offa)
- Update checkout action to v3
- Update Required CMake version
- Cleanup old CI settings
- Sergey Vidyuk (@VestniK)
- Fix for case when vector iterator is raw pointer
- Kfir Gollan (@kfirgollan)
- Add installation example with checkinstall and cmake
- Martin Tournoij (@arp242)
- Escape control characters in keys
- @DavidKorczynski
- Add fuzzing test based on ClusterFuzzLite
- Esonhugh Skyworship (@Esonhugh)
- Fix function signature of
strerror_r
on macos
- Fix function signature of
- Alberto (@0X1A)
- Fix issues with CMake package configuration when used with vcpkg
- Egor Pugin (@egorpugin)
- Fix incorrect operator<<() argument type that gives build error
- Andreas Keller (@andreaskeller96)
- Fix not checking for \r\n when parsing line comments
- 萧迩珀 (@CDK6182CHR)
- Support template into_toml members
This product is licensed under the terms of the MIT License.
- Copyright (c) 2017-2024 Toru Niina
All rights reserved.