From 5d23f4b8a8d4ebb8b33223295a62b453551dccd0 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 27 Jun 2024 15:08:22 +0000 Subject: [PATCH 01/14] feat [skip ci]: update single_include --- single_include/toml.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/single_include/toml.hpp b/single_include/toml.hpp index 51038e0..2cb762a 100644 --- a/single_include/toml.hpp +++ b/single_include/toml.hpp @@ -3584,7 +3584,7 @@ struct has_specialized_into_impl template static std::false_type check(...); template)> - static std::true_type check(::toml::from*); + static std::true_type check(::toml::into*); }; From d00c0c1b1503ebe8267cb044a666413634761fee Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Fri, 28 Jun 2024 23:52:58 +0900 Subject: [PATCH 02/14] doc: explain a macro to link pre-built lib --- README.md | 10 +++++++++- README_ja.md | 10 +++++++++- docs/content.en/docs/installation/_index.md | 8 ++++++++ docs/content.ja/docs/installation/_index.md | 8 ++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d9e3afb..ed72f14 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [日本語版](https://github.com/ToruNiina/toml11/blob/main/README_ja.md) -toml11 is a feature-rich TOML language library for C++. +toml11 is a feature-rich TOML language library for C++11/14/17/20. - It complies with [the latest TOML language specification](https://toml.io/en/v1.0.0). - It passes all the standard TOML language [test cases](https://github.com/toml-lang/toml-test). @@ -124,6 +124,14 @@ $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON -DCMAKE_CXX_STANDARD=11/14/17/20 $ cmake --build ./build/ ``` +When linking the library, use `target_link_libraries` in CMake + +```cmake +target_link_libraries(your_target PUBLIC toml11::toml11) +``` + +or pass `-DTOML11_COMPILE_SOURCES` to the compiler. + ### Building Example To compile the examples in the `examples/` directory, set `-DTOML11_BUILD_EXAMPLES=ON`. diff --git a/README_ja.md b/README_ja.md index 2c98aca..5af24f2 100644 --- a/README_ja.md +++ b/README_ja.md @@ -5,7 +5,7 @@ [![License](https://img.shields.io/github/license/ToruNiina/toml11.svg?style=flat)](LICENSE) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1209136.svg)](https://doi.org/10.5281/zenodo.1209136) -toml11は、C++のための豊富な機能を持つTOML言語ライブラリです。 +toml11は、C++11,14,17,20のための豊富な機能を持つTOML言語ライブラリです。 - [TOML言語の最新規格](https://toml.io/ja/v1.0.0)に準拠しています。 - TOML言語標準のテストケースすべてにパスしています。 @@ -122,6 +122,14 @@ $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON -DCMAKE_CXX_STANDARD=11/14/17/20 $ cmake --build ./build/ ``` +ライブラリをリンクする場合は、CMakeで + +```cmake +target_link_libraries(your_target PUBLIC toml11::toml11) +``` + +とするか、コンパイラに`-DTOML11_COMPILE_SOURCES`を渡してください。 + ### Building example `-DTOML11_BUILD_EXAMPLES=ON`とすることで、`examples/`をコンパイルできます。 diff --git a/docs/content.en/docs/installation/_index.md b/docs/content.en/docs/installation/_index.md index 462879a..d20be76 100644 --- a/docs/content.en/docs/installation/_index.md +++ b/docs/content.en/docs/installation/_index.md @@ -54,6 +54,14 @@ By defining `-DTOML11_PRECOMPILE=ON` when running cmake, you can precompile some $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON ``` +When linking the library, use `target_link_libraries` in CMake + +```cmake +target_link_libraries(your_target PUBLIC toml11::toml11) +``` + +or pass `-DTOML11_COMPILE_SOURCES` to the compiler to suppress header-only features. + However, since toml11 supports multiple C++ versions and may switch types based on the value of `__cplusplus`, there is a possibility of link failures if the version used during build differs from the version used during usage. If you encounter issues, set the required version using `CMAKE_CXX_STANDARD` during compilation. diff --git a/docs/content.ja/docs/installation/_index.md b/docs/content.ja/docs/installation/_index.md index a67be0f..1b326cc 100644 --- a/docs/content.ja/docs/installation/_index.md +++ b/docs/content.ja/docs/installation/_index.md @@ -54,6 +54,14 @@ target_link_libraries(main PRIVATE toml11::toml11) $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON ``` +ライブラリをリンクする場合は、CMakeで + +```cmake +target_link_libraries(your_target PUBLIC toml11::toml11) +``` + +とするか、ヘッダ内の関数の`inline`化を避けるためにコンパイラに`-DTOML11_COMPILE_SOURCES`を渡してください。 + ただし、toml11は複数のC++バージョンに対応するため、`__cplusplus`の値などによって型を切り替えることがあります。 そのため、ビルドした際のバージョンと使用時のバージョンが異なる場合、リンクに失敗する可能性があります。 問題が生じた場合は`CMAKE_CXX_STANDARD`によって必要なバージョンを設定してコンパイルしてください。 From 5b0ea5e95c154f8d13dc177e9999e2694a67a018 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 30 Jun 2024 00:29:34 +0900 Subject: [PATCH 03/14] fix #249: make sure all the file content is read --- include/toml11/parser.hpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/include/toml11/parser.hpp b/include/toml11/parser.hpp index 66948cd..1622ae8 100644 --- a/include/toml11/parser.hpp +++ b/include/toml11/parser.hpp @@ -3524,7 +3524,7 @@ try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::d // read whole file as a sequence of char assert(fsize >= 0); - std::vector letters(static_cast(fsize)); + std::vector letters(static_cast(fsize), '\0'); is.read(reinterpret_cast(letters.data()), fsize); return detail::parse_impl(std::move(letters), std::move(fname), std::move(s)); @@ -3714,7 +3714,15 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version()) // read whole file as a sequence of char assert(fsize >= 0); std::vector letters(static_cast(fsize)); - std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + if(actual != fsize) + { + return err(std::vector{error_info( + std::string("File size changed: \"") + filename + + std::string("\" make sure that FILE* is in binary mode " + "to avoid LF <-> CRLF conversion"), {} + )}); + } return detail::parse_impl(std::move(letters), std::move(filename), std::move(s)); } @@ -3752,7 +3760,12 @@ parse(FILE* fp, std::string filename, spec s = spec::default_version()) // read whole file as a sequence of char assert(fsize >= 0); std::vector letters(static_cast(fsize)); - std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + if(actual != fsize) + { + throw file_io_error(errno, "File size changed; make sure that " + "FILE* is in binary mode to avoid LF <-> CRLF conversion", filename); + } auto res = detail::parse_impl(std::move(letters), std::move(filename), std::move(s)); if(res.is_ok()) From bcd8a6d1e43ff43d06fbb550f115a640de6702bb Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 30 Jun 2024 00:47:44 +0900 Subject: [PATCH 04/14] doc: update notice about open mode in overload of toml::parse that takes file stream or FILE* itself --- .../content.en/docs/features/parsing_files.md | 16 ++-- docs/content.en/docs/reference/parser.md | 84 ++++++++++-------- .../content.ja/docs/features/parsing_files.md | 20 +++-- docs/content.ja/docs/reference/parser.md | 88 +++++++++++-------- 4 files changed, 118 insertions(+), 90 deletions(-) diff --git a/docs/content.en/docs/features/parsing_files.md b/docs/content.en/docs/features/parsing_files.md index 9239cb9..77a9be4 100644 --- a/docs/content.en/docs/features/parsing_files.md +++ b/docs/content.en/docs/features/parsing_files.md @@ -42,10 +42,18 @@ int main() } ``` +#### Specifying a File with `std::filesystem::path` + +[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can accept a `std::filesystem::path`. + +This requires C++17 or later, as it relies on the `` support. + #### Specifying an Input Stream with `std::istream` [`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can also accept an `std::istream`. +Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library. + Without the filename information, error messages will display `"unknown file"`. To avoid this, you can pass the filename as a `std::string` in the second argument when using `std::istream`. You can use streams other than `std::ifstream`, such as `std::istringstream`. Note that the entire content is readable at the time of the call. @@ -64,16 +72,12 @@ int main() } ``` -#### Specifying a File with `std::filesystem::path` - -[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can accept a `std::filesystem::path`. - -This requires C++17 or later, as it relies on the `` support. - #### Specifying a File with `FILE*` [`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can also accept a `FILE*`. +Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library. + As with `std::istream`, you need to provide the filename as a string in the second argument. When passing a `FILE*`, if the file read fails, `errno` will be reported. diff --git a/docs/content.en/docs/reference/parser.md b/docs/content.en/docs/reference/parser.md index 3b83564..1736139 100644 --- a/docs/content.en/docs/reference/parser.md +++ b/docs/content.en/docs/reference/parser.md @@ -17,23 +17,6 @@ In case of failure, `toml::syntax_error` is thrown. The type information of `basic_value` is provided by a `template`, and the TOML language version is specified by `toml::spec`. -### `parse(std::istream&, std::string filename, toml::spec)` - -```cpp -namespace toml -{ -template -basic_value -parse(std::istream& is, - std::string fname = "unknown file", - spec s = spec::default_version()); -} -``` - -Parses the content of the given `std::istream&`. - -The filename information is taken as the third argument. If the filename is not provided, it defaults to `"unknown file"`. - ### `parse(std::string filename, toml::spec)` ```cpp @@ -90,6 +73,25 @@ If reading the file fails, `toml::file_io_error` is thrown. If parsing fails, `toml::syntax_error` is thrown. +### `parse(std::istream&, std::string filename, toml::spec)` + +```cpp +namespace toml +{ +template +basic_value +parse(std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()); +} +``` + +Parses the content of the given `std::istream&`. + +Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library. + +The filename information is taken as the third argument. If the filename is not provided, it defaults to `"unknown file"`. + ### `parse(FILE*, std::string filename, toml::spec)` ```cpp @@ -105,6 +107,8 @@ parse(FILE* fp, Parses the content of the file pointed to by `FILE*`. +Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library. + If reading the file fails, `file_io_error` containing `errno` is thrown. If parsing fails, `syntax_error` is thrown. @@ -166,27 +170,6 @@ For instance, errors occurring internally within `std::ifstream` or memory exhau {{< /hint >}} -### `try_parse(std::istream&, std::string filename, toml::spec)` - -```cpp -namespace toml -{ -template -result, std::vector> -try_parse(std::istream& is, - std::string fname = "unknown file", - spec s = spec::default_version()); -} -``` - -Takes a `std::istream&` and parses its content. - -The file name information is taken as the second argument. If a file name is not provided, it defaults to `"unknown file"`. - -If parsing fails, a `result` holding the error type `std::vector` is returned. - -If successful, a `result` holding a `basic_value` is returned. - ### `try_parse(std::string filename, toml::spec)` ```cpp @@ -241,6 +224,29 @@ If parsing fails, a `result` holding the error type `std::vector` is If successful, a `result` holding a `basic_value` is returned. +### `try_parse(std::istream&, std::string filename, toml::spec)` + +```cpp +namespace toml +{ +template +result, std::vector> +try_parse(std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()); +} +``` + +Takes a `std::istream&` and parses its content. + +Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library. + +The file name information is taken as the second argument. If a file name is not provided, it defaults to `"unknown file"`. + +If parsing fails, a `result` holding the error type `std::vector` is returned. + +If successful, a `result` holding a `basic_value` is returned. + ### `try_parse(FILE*, std::string filename, toml::spec)` ```cpp @@ -256,6 +262,8 @@ try_parse(FILE* fp, Takes a `FILE*` and parses its content. +Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library. + If parsing fails, a `result` holding the error type `std::vector` is returned. If successful, a `result` holding a `basic_value` is returned. diff --git a/docs/content.ja/docs/features/parsing_files.md b/docs/content.ja/docs/features/parsing_files.md index d917f6c..0308bd3 100644 --- a/docs/content.ja/docs/features/parsing_files.md +++ b/docs/content.ja/docs/features/parsing_files.md @@ -44,11 +44,21 @@ int main() } ``` +#### `std::filesystem::path`でファイルを指定する + +[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) +には、`std::filesystem::path`を渡すことも可能です。 + +当然ですが、``がサポートされるC++17以降でなければ使用できません。 + #### `std::istream`で入力ストリームを指定する [`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) には、`std::istream`を渡すことも可能です。 +標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、 +`std::ios::binary`を使ってバイナリモードで開いてください。 + その際、ファイル名の情報がなくなるため、エラーメッセージ中では `"unknown file"` となります。 これを避けるため、 `std::istream` を取る場合は第二引数に `std::string` でファイル名を取ることもできます。 @@ -70,18 +80,14 @@ int main() } ``` -#### `std::filesystem::path`でファイルを指定する - -[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) -には、`std::filesystem::path`を渡すことも可能です。 - -当然ですが、``がサポートされるC++17以降でなければ使用できません。 - #### `FILE*`でファイルを指定する [`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) には、`FILE*`を渡すことも可能です。 +標準ライブラリによる改行文字の自動変換によるファイルサイズと文字数との不整合を避けるため、 +`fopen("example.toml", "rb")`のようにしてバイナリモードで開いてください。 + この場合も、`std::istream`のときと同様に、第二引数に文字列でファイル名を与える必要があります。 `FILE*`を渡した場合、ファイルの読み込みに失敗した際には`errno`が報告されます。 diff --git a/docs/content.ja/docs/reference/parser.md b/docs/content.ja/docs/reference/parser.md index e9465a8..d9cdc99 100644 --- a/docs/content.ja/docs/reference/parser.md +++ b/docs/content.ja/docs/reference/parser.md @@ -17,23 +17,6 @@ type = "docs" `basic_value`の持つ型情報は`template`で、TOML言語のバージョンは`toml::spec`で指定します。 -### `parse(std::istream&, std::string filename, toml::spec)` - -```cpp -namespace toml -{ -template -basic_value -parse(std::istream& is, - std::string fname = "unknown file", - spec s = spec::default_version()); -} -``` - -`std::istream&`を受け取ってその内容をパースします。 - -ファイル名の情報は第三引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。 - ### `parse(std::string filename, toml::spec)` ```cpp @@ -90,6 +73,25 @@ parse(const std::filesystem::path& fpath, パースに失敗した場合、`syntax_error`が送出されます。 +### `parse(std::istream&, std::string filename, toml::spec)` + +```cpp +namespace toml +{ +template +basic_value +parse(std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()); +} +``` + +`std::istream&`を受け取ってその内容をパースします。 + +標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、 +`std::ios::binary`を使ってバイナリモードで開いてください。 + +ファイル名の情報は第三引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。 ### `parse(FILE*, std::string filename, toml::spec)` @@ -106,6 +108,9 @@ parse(FILE* fp, `FILE*`が指すファイルを読み込んでパースします。 +標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、 +`fopen`には`"rb"`などを渡してバイナリモードで開いてください。 + ファイルの読み込みに失敗した場合、`errno`が含まれた`file_io_error`が送出されます。 パースに失敗した場合、`syntax_error`が送出されます。 @@ -167,28 +172,6 @@ parse_str(std::string content, {{< /hint >}} - -### `try_parse(std::istream&, std::string filename, toml::spec)` - -```cpp -namespace toml -{ -template -result, std::vector> -try_parse(std::istream& is, - std::string fname = "unknown file", - spec s = spec::default_version()); -} -``` - -`std::istream&`を受け取ってその内容をパースします。 - -ファイル名の情報は第二引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。 - -パースに失敗した場合、エラー型である`std::vector`を持つ`result`が返されます。 - -成功した場合、`basic_value`を持つ`result`が返されます。 - ### `try_parse(std::string filename, toml::spec)` ```cpp @@ -244,6 +227,30 @@ try_parse(const std::filesystem::path& fpath, 成功した場合、`basic_value`を持つ`result`が返されます。 +### `try_parse(std::istream&, std::string filename, toml::spec)` + +```cpp +namespace toml +{ +template +result, std::vector> +try_parse(std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()); +} +``` + +`std::istream&`を受け取ってその内容をパースします。 + +標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、 +`std::ios::binary`を使ってバイナリモードで開いてください。 + +ファイル名の情報は第二引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。 + +パースに失敗した場合、エラー型である`std::vector`を持つ`result`が返されます。 + +成功した場合、`basic_value`を持つ`result`が返されます。 + ### `try_parse(FILE*, std::string filename, toml::spec)` ```cpp @@ -259,6 +266,9 @@ try_parse(FILE* fp, `FILE*`を受け取って、そのファイルの内容をパースします。 +標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、 +`fopen`には`"rb"`などを渡してバイナリモードで開いてください。 + パースに失敗した場合、エラー型である`std::vector`を持つ`result`が返されます。 成功した場合、`basic_value`を持つ`result`が返されます。 From de092e5457f8c34dcc8570b05291d6923be71cfd Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 30 Jun 2024 00:55:45 +0900 Subject: [PATCH 05/14] fix: cast fsize to avoid sign-conv --- include/toml11/parser.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/toml11/parser.hpp b/include/toml11/parser.hpp index 1622ae8..5952f99 100644 --- a/include/toml11/parser.hpp +++ b/include/toml11/parser.hpp @@ -3715,7 +3715,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version()) assert(fsize >= 0); std::vector letters(static_cast(fsize)); const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); - if(actual != fsize) + if(actual != static_cast(fsize)) { return err(std::vector{error_info( std::string("File size changed: \"") + filename + @@ -3761,7 +3761,7 @@ parse(FILE* fp, std::string filename, spec s = spec::default_version()) assert(fsize >= 0); std::vector letters(static_cast(fsize)); const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); - if(actual != fsize) + if(actual != static_cast(fsize)) { throw file_io_error(errno, "File size changed; make sure that " "FILE* is in binary mode to avoid LF <-> CRLF conversion", filename); From 9f59c591f04b66363076131191f3582499474fa6 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sat, 29 Jun 2024 15:56:19 +0000 Subject: [PATCH 06/14] feat [skip ci]: update single_include --- single_include/toml.hpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/single_include/toml.hpp b/single_include/toml.hpp index 2cb762a..71176fc 100644 --- a/single_include/toml.hpp +++ b/single_include/toml.hpp @@ -15063,7 +15063,7 @@ try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::d // read whole file as a sequence of char assert(fsize >= 0); - std::vector letters(static_cast(fsize)); + std::vector letters(static_cast(fsize), '\0'); is.read(reinterpret_cast(letters.data()), fsize); return detail::parse_impl(std::move(letters), std::move(fname), std::move(s)); @@ -15253,7 +15253,15 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version()) // read whole file as a sequence of char assert(fsize >= 0); std::vector letters(static_cast(fsize)); - std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + if(actual != static_cast(fsize)) + { + return err(std::vector{error_info( + std::string("File size changed: \"") + filename + + std::string("\" make sure that FILE* is in binary mode " + "to avoid LF <-> CRLF conversion"), {} + )}); + } return detail::parse_impl(std::move(letters), std::move(filename), std::move(s)); } @@ -15291,7 +15299,12 @@ parse(FILE* fp, std::string filename, spec s = spec::default_version()) // read whole file as a sequence of char assert(fsize >= 0); std::vector letters(static_cast(fsize)); - std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + if(actual != static_cast(fsize)) + { + throw file_io_error(errno, "File size changed; make sure that " + "FILE* is in binary mode to avoid LF <-> CRLF conversion", filename); + } auto res = detail::parse_impl(std::move(letters), std::move(filename), std::move(s)); if(res.is_ok()) From 1d3abc971829c172c03352934b2ee56c04f9771e Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 30 Jun 2024 17:40:40 +0900 Subject: [PATCH 07/14] ci: remove verbose message from ci build --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ab68676..a745a14 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,7 +53,7 @@ jobs: sudo apt-get install clang-${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_VERBOSE_MAKEFILE=1 -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} - name: Build run: | cmake --build build/ From fc493afb4e0fa73a15e07bc621901a39109fda52 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 30 Jun 2024 23:59:23 +0900 Subject: [PATCH 08/14] chore: update version 4.0.2 --- include/toml11/version.hpp | 2 +- single_include/toml.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/toml11/version.hpp b/include/toml11/version.hpp index 778fc2b..d46f14f 100644 --- a/include/toml11/version.hpp +++ b/include/toml11/version.hpp @@ -3,7 +3,7 @@ #define TOML11_VERSION_MAJOR 4 #define TOML11_VERSION_MINOR 0 -#define TOML11_VERSION_PATCH 1 +#define TOML11_VERSION_PATCH 2 #ifndef __cplusplus # error "__cplusplus is not defined" diff --git a/single_include/toml.hpp b/single_include/toml.hpp index 71176fc..c7de7d7 100644 --- a/single_include/toml.hpp +++ b/single_include/toml.hpp @@ -3,7 +3,7 @@ #define TOML11_VERSION_MAJOR 4 #define TOML11_VERSION_MINOR 0 -#define TOML11_VERSION_PATCH 1 +#define TOML11_VERSION_PATCH 2 #ifndef __cplusplus # error "__cplusplus is not defined" From ccd941dc5bb1d3cda7b18552c470f57c6c92f55d Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 2 Jul 2024 00:03:10 +0900 Subject: [PATCH 09/14] fix: remove default arg from fwd decl --- include/toml_fwd.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/toml_fwd.hpp b/include/toml_fwd.hpp index af9ada6..3ba77ff 100644 --- a/include/toml_fwd.hpp +++ b/include/toml_fwd.hpp @@ -52,8 +52,7 @@ struct local_time_format_info; struct array_format_info; struct table_format_info; -template, - typename Allocator = std::allocator>> +template class ordered_map; struct syntax_error; From d4742334cef2a5e9fcb9349ba7e8a14788614cf0 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 2 Jul 2024 23:34:20 +0900 Subject: [PATCH 10/14] fix: add detail::make_error_info_rec overload that converts basic_value to location --- include/toml11/fwd/error_info_fwd.hpp | 8 ++++++++ include/toml11/value.hpp | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/include/toml11/fwd/error_info_fwd.hpp b/include/toml11/fwd/error_info_fwd.hpp index 5d30b86..5b8600c 100644 --- a/include/toml11/fwd/error_info_fwd.hpp +++ b/include/toml11/fwd/error_info_fwd.hpp @@ -41,6 +41,10 @@ struct error_info std::string suffix_; // hint or something like that }; +// forward decl +template +class basic_value; + namespace detail { inline error_info make_error_info_rec(error_info e) @@ -53,6 +57,10 @@ inline error_info make_error_info_rec(error_info e, std::string s) return e; } +template +error_info make_error_info_rec(error_info e, + const basic_value& v, std::string msg, Ts&& ... tail); + template error_info make_error_info_rec(error_info e, source_location loc, std::string msg, Ts&& ... tail) diff --git a/include/toml11/value.hpp b/include/toml11/value.hpp index fe1720d..6139ad9 100644 --- a/include/toml11/value.hpp +++ b/include/toml11/value.hpp @@ -2026,12 +2026,16 @@ operator>=(const basic_value& lhs, const basic_value& rhs) } // error_info helper +namespace detail +{ template error_info make_error_info_rec(error_info e, const basic_value& v, std::string msg, Ts&& ... tail) { return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward(tail)...); } +} // detail + template error_info make_error_info( std::string title, const basic_value& v, std::string msg, Ts&& ... tail) From 37d0391b9d24cce5d8baca878b413c297940d48a Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 2 Jul 2024 23:35:16 +0900 Subject: [PATCH 11/14] test: add test to make error_info check if it compiles --- tests/CMakeLists.txt | 1 + tests/test_error_message.cpp | 79 ++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/test_error_message.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3ca04aa..d95901e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ set(TOML11_TEST_NAMES test_comments test_datetime + test_error_message test_find test_find_or test_format_integer diff --git a/tests/test_error_message.cpp b/tests/test_error_message.cpp new file mode 100644 index 0000000..567dc4a --- /dev/null +++ b/tests/test_error_message.cpp @@ -0,0 +1,79 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" + +#include + +TEST_CASE("testing custom error message using source_location") +{ + const toml::value root = toml::parse_str(R"( + range = [0, 42] + val = 54 + )"); + + const auto& lower = root.at("range").at(0); + const auto& upper = root.at("range").at(1); + const auto& val = root.at("val"); + + const auto err = toml::make_error_info("val not in range", + lower.location(), "lower limit is defined here", + upper.location(), "upper limit is defined here", + val.location(), "this is not in the range", + "Hint: upper limit is inclusive" + ); + + CHECK_EQ(err.title(), "val not in range"); + CHECK_EQ(err.locations().size(), 3); + CHECK_EQ(err.locations().at(0).second, "lower limit is defined here"); + CHECK_EQ(err.locations().at(1).second, "upper limit is defined here"); + CHECK_EQ(err.locations().at(2).second, "this is not in the range" ); +} + +TEST_CASE("testing custom error message using value") +{ + const toml::value root = toml::parse_str(R"( + range = [0, 42] + val = 54 + )"); + + const auto& lower = root.at("range").at(0); + const auto& upper = root.at("range").at(1); + const auto& val = root.at("val"); + + const auto err = toml::make_error_info("val not in range", + lower, "lower limit is defined here", + upper, "upper limit is defined here", + val, "this is not in the range", + "Hint: upper limit is inclusive" + ); + + CHECK_EQ(err.title(), "val not in range"); + CHECK_EQ(err.locations().size(), 3); + CHECK_EQ(err.locations().at(0).second, "lower limit is defined here"); + CHECK_EQ(err.locations().at(1).second, "upper limit is defined here"); + CHECK_EQ(err.locations().at(2).second, "this is not in the range" ); +} + +TEST_CASE("testing custom error message using source_location and value") +{ + const toml::value root = toml::parse_str(R"( + range = [0, 42] + val = 54 + )"); + + const auto& lower = root.at("range").at(0); + const auto& upper = root.at("range").at(1); + const auto& val = root.at("val"); + + const auto err = toml::make_error_info("val not in range", + lower, "lower limit is defined here", + upper, "upper limit is defined here", + val.location(), "this is not in the range", + "Hint: upper limit is inclusive" + ); + + CHECK_EQ(err.title(), "val not in range"); + CHECK_EQ(err.locations().size(), 3); + CHECK_EQ(err.locations().at(0).second, "lower limit is defined here"); + CHECK_EQ(err.locations().at(1).second, "upper limit is defined here"); + CHECK_EQ(err.locations().at(2).second, "this is not in the range" ); +} From 65e722da43d431eb97147ed02b067ea8a2333b15 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 3 Jul 2024 00:00:50 +0900 Subject: [PATCH 12/14] test: add minimum cases of serializer --- tests/CMakeLists.txt | 1 + tests/test_serialize.cpp | 148 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 tests/test_serialize.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3ca04aa..8c8afde 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,6 +22,7 @@ set(TOML11_TEST_NAMES test_parse_table test_result test_scanner + test_serialize test_syntax_boolean test_syntax_integer test_syntax_floating diff --git a/tests/test_serialize.cpp b/tests/test_serialize.cpp new file mode 100644 index 0000000..b403ebc --- /dev/null +++ b/tests/test_serialize.cpp @@ -0,0 +1,148 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" + +#include + +TEST_CASE("testing serialization") +{ + using namespace toml::literals::toml_literals; + + const auto spec_example = R"(# This is a TOML document + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +dob = 1979-05-27T07:32:00-08:00 + +[database] +enabled = true +ports = [ 8000, 8001, 8002 ] +data = [ ["delta", "phi"], [3.14] ] +temp_targets = { cpu = 79.5, case = 72.0 } + +[servers] + +[servers.alpha] +ip = "10.0.0.1" +role = "frontend" + +[servers.beta] +ip = "10.0.0.2" +role = "backend")"_toml; + + // format and parse + const auto v = toml::parse_str(toml::format(spec_example)); + + CHECK_EQ(v, spec_example); +} + +TEST_CASE("testing serialization with complicated keys") +{ + using namespace toml::literals::toml_literals; + + const auto spec_example = R"( +[keys] + +key = "value" +bare_key = "value" +bare-key = "value" +1234 = "value" + +"127.0.0.1" = "value" +"character encoding" = "value" +"ʎǝʞ" = "value" +'key2' = "value" +'quoted "value"' = "value" + +"" = "blank" + +fruits.apple.skin = "thin" +fruits.apple.color = "red" + +fruits.orange.skin = "thick" +fruits.orange.color = "orange" + +site."google.com" = true +3.14159 = "pi" +)"_toml; + + // format and parse + const auto v = toml::parse_str(toml::format(spec_example)); + + CHECK_EQ(v, spec_example); +} + +TEST_CASE("testing serialization with array of tables") +{ + using namespace toml::literals::toml_literals; + + const auto spec_example = R"( +points = [ { x = 1, y = 2, z = 3 }, + { x = 7, y = 8, z = 9 }, + { x = 2, y = 4, z = 8 } ] + +[[products]] +name = "Hammer" +sku = 738594937 + +[[products]] # empty table within the array + +[[products]] +name = "Nail" +sku = 284758393 + +color = "gray" + +[[fruits]] +name = "apple" + +[fruits.physical] # subtable +color = "red" +shape = "round" + +[[fruits.varieties]] # nested array of tables +name = "red delicious" + +[[fruits.varieties]] +name = "granny smith" + +[[fruits]] +name = "banana" + +[[fruits.varieties]] +name = "plantain" +)"_toml; + + // format and parse + const auto v = toml::parse_str(toml::format(spec_example)); + + CHECK_EQ(v, spec_example); +} + +TEST_CASE("testing serialization with locale") +{ + std::string current_locale = std::setlocale(LC_ALL, nullptr); + + // fr_FR is a one of locales that uses `,` as a decimal separator. + if(const char* try_hyphen = std::setlocale(LC_ALL, "fr_FR.UTF-8")) + { + current_locale = std::string(try_hyphen); + } + else if(const char* try_nohyphen = std::setlocale(LC_ALL, "fr_FR.utf8")) + { + current_locale = std::string(try_nohyphen); + } + + MESSAGE("current_locale = ", current_locale); + + const auto v1 = toml::parse_str(R"( + pi = 3.1415_9265 + large_int = 123_456_789 + )"); + const auto v2 = toml::parse_str(toml::format(v1)); + + // actually, it checkl if v1 is serialized correctly under FR locale + // where 3.1415 -> 3,1415 + CHECK_EQ(v1, v2); +} From b9b2ee02ff63aa93bce07ba5209c905e585d7637 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 2 Jul 2024 15:23:57 +0000 Subject: [PATCH 13/14] feat [skip ci]: update single_include --- single_include/toml.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/single_include/toml.hpp b/single_include/toml.hpp index c7de7d7..57ec3d6 100644 --- a/single_include/toml.hpp +++ b/single_include/toml.hpp @@ -5447,6 +5447,10 @@ struct error_info std::string suffix_; // hint or something like that }; +// forward decl +template +class basic_value; + namespace detail { inline error_info make_error_info_rec(error_info e) @@ -5459,6 +5463,10 @@ inline error_info make_error_info_rec(error_info e, std::string s) return e; } +template +error_info make_error_info_rec(error_info e, + const basic_value& v, std::string msg, Ts&& ... tail); + template error_info make_error_info_rec(error_info e, source_location loc, std::string msg, Ts&& ... tail) @@ -7588,12 +7596,16 @@ operator>=(const basic_value& lhs, const basic_value& rhs) } // error_info helper +namespace detail +{ template error_info make_error_info_rec(error_info e, const basic_value& v, std::string msg, Ts&& ... tail) { return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward(tail)...); } +} // detail + template error_info make_error_info( std::string title, const basic_value& v, std::string msg, Ts&& ... tail) From 973ecee32de78130e2a7cad5e3a1cb2036eb5c62 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 3 Jul 2024 00:24:45 +0900 Subject: [PATCH 14/14] fix: add missing include file --- tests/test_serialize.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_serialize.cpp b/tests/test_serialize.cpp index b403ebc..4f780a3 100644 --- a/tests/test_serialize.cpp +++ b/tests/test_serialize.cpp @@ -3,6 +3,8 @@ #include +#include + TEST_CASE("testing serialization") { using namespace toml::literals::toml_literals;