added toml::yaml_formatter

also:
- fixed parser not correctly round-tripping int format in some cases
- added `TOML_ENABLE_FORMATTERS` option
- added `operator->` to `toml::value`
- refactoring
This commit is contained in:
Mark Gillard 2021-11-02 22:13:09 +02:00
parent 0ffd23d73f
commit 7b50df796f
30 changed files with 1403 additions and 731 deletions

View File

@ -24,7 +24,7 @@
- Proper UTF-8 handling (incl. BOM)
- Works with or without exceptions
- Doesn't require RTTI
- First-class support for serializing to JSON
- First-class support for serializing to JSON and YAML
- Tested on Clang (6+), GCC (7+) and MSVC (VS2019)
- Tested on x64, x86 and ARM
@ -79,6 +79,8 @@ 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].
@ -97,13 +99,13 @@ You'll find some more code examples in the `examples` directory, and plenty more
2. `#include <toml++/toml.h>`
### Conan
Add `tomlplusplus/2.5.0` to your conanfile.
Add `tomlplusplus/3.0.0` to your conanfile.
### DDS
Add `tomlpp` to your `package.json5`, e.g.:
```
depends: [
'tomlpp^2.5.0',
'tomlpp^3.0.0',
]
```
> &#xFE0F; _[What is DDS?](https://dds.pizza/)_
@ -119,7 +121,7 @@ include(FetchContent)
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v2.5.0
GIT_TAG v3.0.0
)
FetchContent_MakeAvailable(tomlplusplus)
```
@ -136,22 +138,21 @@ assured that I fully support it being added, and welcome [pull requests](./CONTR
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 | Default | Description |
|-----------------------------------|:--------------:|--------------------------|----------------------------------------------------------------------------------------------------------------------|
| `TOML_API` | define | undefined | API annotation to add to public symbols (e.g. `__declspec(dllexport)` on Windows). |
| `TOML_ASSERT(expr)` | function macro | `assert()` | Sets the assert function used by the library. |
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_ENABLE_JSON_FORMATTER` | boolean | `1` | Enables the JSON formatter. Set to `0` if you don't need it to improve compile times and binary size. |
| `TOML_ENABLE_TOML_FORMATTER` | boolean | `1` | Enables the TOML formatter. Set to `0` if you don't need it to improve compile times and binary size. |
| `TOML_ENABLE_PARSER` | boolean | `1` | Enables the parser. Set to `0` if you don't need it to improve compile times and binary size. |
| `TOML_ENABLE_UNRELEASED_FEATURES` | boolean | `0` | Enables support for [unreleased TOML language features. |
| `TOML_ENABLE_WINDOWS_COMPAT` | boolean | `1` on Windows | Enables support for transparent conversion between wide and narrow strings. |
| `TOML_EXCEPTIONS` | boolean | your compiler's settings | Sets whether the library uses exceptions. |
| `TOML_HEADER_ONLY` | boolean | `1` | Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library). |
| `TOML_IMPLEMENTATION` | define | undefined | Define this to enable compilation of the library's implementation when `TOML_HEADER_ONLY` == `0`. |
| `TOML_OPTIONAL_TYPE` | type name | undefined | Overrides the `optional<T>` type used by the library if you need [something better than std::optional]. |
| `TOML_SMALL_FLOAT_TYPE` | type name | undefined | If your codebase has an additional 'small' float type (e.g. half-precision), this tells toml++ about it. |
| `TOML_SMALL_INT_TYPE` | type name | undefined | If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it. |
| Option | Type | Default | Description |
|-----------------------------------|:--------------:|--------------------------|---------------------------------------------------------------------------------------------------------------|
| `TOML_API` | define | undefined | API annotation to add to public symbols (e.g. `__declspec(dllexport)` on Windows). |
| `TOML_ASSERT(expr)` | function macro | `assert()` | Sets the assert function used by the library. |
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_ENABLE_FORMATTERS` | boolean | `1` | Enables the formatters. Set to `0` if you don't need them to improve compile times and binary size. |
| `TOML_ENABLE_PARSER` | boolean | `1` | Enables the parser. Set to `0` if you don't need it to improve compile times and binary size. |
| `TOML_ENABLE_UNRELEASED_FEATURES` | boolean | `0` | Enables support for [unreleased TOML language features. |
| `TOML_ENABLE_WINDOWS_COMPAT` | boolean | `1` on Windows | Enables support for transparent conversion between wide and narrow strings. |
| `TOML_EXCEPTIONS` | boolean | match compiler settings | Sets whether the library uses exceptions. |
| `TOML_HEADER_ONLY` | boolean | `1` | Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library). |
| `TOML_IMPLEMENTATION` | define | undefined | Define this to enable compilation of the library's implementation when `TOML_HEADER_ONLY` == `0`. |
| `TOML_OPTIONAL_TYPE` | type name | undefined | Overrides the `optional<T>` type used by the library if you need [something better than std::optional]. |
| `TOML_SMALL_FLOAT_TYPE` | type name | undefined | If your codebase has an additional 'small' float type (e.g. half-precision), this tells toml++ about it. |
| `TOML_SMALL_INT_TYPE` | type name | undefined | If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it. |
> &#xFE0F; _A number of these have ABI implications; the library uses inline namespaces to prevent you from accidentally
linking incompatible combinations together._

View File

@ -9,6 +9,7 @@
#define TOML_CONST_GETTER
#define TOML_CONST_INLINE_GETTER inline
#define TOML_CONSTRAINED_TEMPLATE(cond, ...) template <__VA_ARGS__>
#define TOML_HIDDEN_CONSTRAINT(cond, ...) template <__VA_ARGS__>
#define TOML_EMPTY_BASES
#define TOML_EXTERN
#define TOML_EXTERN_NOEXCEPT(...)

View File

@ -9,7 +9,7 @@
\section mainpage-features Features
- Supports the latest [TOML](https://toml.io/) release ([v1.0.0](https://toml.io/en/v1.0.0)), plus
optional support for some unreleased TOML features
- Supports serializing to JSON
- 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)
- Header-only (optional!)
@ -130,7 +130,7 @@
\subsection mainpage-example-parsing-without-exceptions Handling errors without exceptions
Can't (or won't) use exceptions? That's fine too. You can disable exceptions in your compiler flags and/or
explicitly disable the library's use of them by setting the option \ref TOML_EXCEPTIONS to `0`. In either case,
explicitly disable the library's use of them by setting the option #TOML_EXCEPTIONS to `0`. In either case,
the parsing functions return a toml::parse_result instead of a toml::table:
\cpp
@ -290,10 +290,10 @@
\subsection mainpage-example-serialization Serializing as TOML and JSON
\subsection mainpage-example-serialization Serializing as TOML, JSON and YAML
All toml++ data types have overloaded `operator<<` for ostreams, so 'serializing' a set of TOML data to actual
TOML is done just by printing it to an ostream. Converting it to JSON is done in the same way,
but via a toml::json_formatter.
TOML is done just by printing it to an ostream. Converting it to JSON and YAML is done in much the same way,
but via a toml::json_formatter and toml::yaml_formatter.
\godbolt{MMNoW4}
@ -323,6 +323,10 @@
// serializing as JSON using toml::json_formatter:
std::cout << "###### JSON ######" << "\n\n";
std::cout << toml::json_formatter{ tbl } << "\n\n";
// serializing as YAML using toml::yaml_formatter:
std::cout << "###### YAML ######" << "\n\n";
std::cout << toml::yaml_formatter{ tbl } << "\n\n";
return 0;
}
\ecpp
@ -360,10 +364,14 @@
"and beyond"
]
}
###### YAML ######
\eout
\see
- toml::toml_formatter
- toml::json_formatter
- toml::yaml_formatter
@ -373,7 +381,7 @@
a large number of translation units. You can counter this by disabling header-only mode and explicitly controlling
where the library's implementation is compiled.
<strong>Step 1: Set \ref TOML_HEADER_ONLY to [code]0[/code] before including toml++</strong>
<strong>Step 1: Set #TOML_HEADER_ONLY to [code]0[/code] before including toml++</strong>
This must be the same everywhere, so either set it as a global `#define` in your build system, or
do it manually before including toml++ in some global header that's used everywhere in your project:
@ -384,7 +392,7 @@
#include <toml.hpp>
\ecpp
<strong>Step 2: Define \ref TOML_IMPLEMENTATION before including toml++ in one specific translation unit</strong>
<strong>Step 2: Define #TOML_IMPLEMENTATION before including toml++ in one specific translation unit</strong>
\cpp
// some_code_file.cpp
@ -397,7 +405,7 @@
Some library features can be disabled wholesale so you can avoid paying their the compilation cost if you don't need them.
For example, if all you need to do is serialize some code-generated TOML and don't actually need the parser at all you, can
set \ref TOML_ENABLE_PARSER to `0` to disable the parser altogether. This can yield fairly significant compilation
set #TOML_ENABLE_PARSER to `0` to disable the parser altogether. This can yield fairly significant compilation
speedups since the parser accounts for a good chunk of the library's code.
@ -428,7 +436,7 @@
\subsection mainpage-adding-lib-conan Conan
Add `tomlplusplus/2.5.0` to your conanfile.
Add `tomlplusplus/3.0.0` to your conanfile.
@ -436,7 +444,7 @@
Add `tomlpp` to your `package.json5`, e.g.:
\bash
depends: [
'tomlpp^2.5.0',
'tomlpp^3.0.0',
]
\ebash
@ -463,7 +471,7 @@
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v2.5.0
GIT_TAG v3.0.0
)
FetchContent_MakeAvailable(tomlplusplus)
\endcode

View File

@ -1358,11 +1358,11 @@ TOML_NAMESPACE_START
/// @}
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the array out to a stream as formatted TOML.
///
/// \availability This operator is only available when #TOML_ENABLE_TOML_FORMATTER is enabled.
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& lhs, const array& rhs)
{
impl::print_to_stream(lhs, rhs);

View File

@ -4,6 +4,9 @@
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
#if TOML_ENABLE_FORMATTERS
#include "forward_declarations.h"
#include "print_to_stream.h"
#include "header_start.h"
@ -13,9 +16,15 @@ TOML_IMPL_NAMESPACE_START
{
struct formatter_constants
{
std::string_view pos_inf;
std::string_view neg_inf;
std::string_view nan;
format_flags mandatory_flags;
format_flags ignored_flags;
std::string_view float_pos_inf;
std::string_view float_neg_inf;
std::string_view float_nan;
std::string_view bool_true;
std::string_view bool_false;
};
struct formatter_config
@ -34,6 +43,7 @@ TOML_IMPL_NAMESPACE_START
const formatter_constants* constants_;
formatter_config config_;
size_t indent_columns_;
format_flags int_format_mask_;
std::ostream* stream_; //
int indent_; // these are set in attach()
bool naked_newline_; //
@ -90,47 +100,12 @@ TOML_IMPL_NAMESPACE_START
return !!(config_.flags & format_flags::indent_sub_tables);
}
TOML_PURE_INLINE_GETTER
bool quote_dates_and_times() const noexcept
{
return !!(config_.flags & format_flags::quote_dates_and_times);
}
TOML_PURE_INLINE_GETTER
bool quote_infinities_and_nans() const noexcept
{
return !!(config_.flags & format_flags::quote_infinities_and_nans);
}
TOML_PURE_INLINE_GETTER
bool literal_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_literal_strings);
}
TOML_PURE_INLINE_GETTER
bool multi_line_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_multi_line_strings);
}
TOML_PURE_INLINE_GETTER
bool value_format_flags_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_value_format_flags);
}
TOML_PURE_INLINE_GETTER
bool naked_newline() const noexcept
{
return naked_newline_;
}
void clear_naked_newline() noexcept
{
naked_newline_ = false;
}
TOML_API
void attach(std::ostream& stream) noexcept;
@ -143,6 +118,12 @@ TOML_IMPL_NAMESPACE_START
TOML_API
void print_indent();
TOML_API
void print_unformatted(char);
TOML_API
void print_unformatted(std::string_view);
TOML_API
void print_string(std::string_view str, bool allow_multi_line = true, bool allow_bare = false);
@ -183,3 +164,4 @@ TOML_IMPL_NAMESPACE_END;
/// \endcond
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -4,12 +4,13 @@
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "print_to_stream.h"
@ -38,9 +39,15 @@ TOML_IMPL_NAMESPACE_START
{
TOML_ASSERT(source_ != nullptr);
config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;
indent_columns_ = {};
for (auto c : config_.indent)
indent_columns_ += c == '\t' ? 4u : 1u;
int_format_mask_ = config_.flags
& (format_flags::allow_binary_integers | format_flags::allow_octal_integers
| format_flags::allow_hexadecimal_integers);
}
TOML_EXTERNAL_LINKAGE
@ -77,6 +84,20 @@ TOML_IMPL_NAMESPACE_START
}
}
TOML_EXTERNAL_LINKAGE
void formatter::print_unformatted(char c)
{
print_to_stream(*stream_, c);
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print_unformatted(std::string_view str)
{
print_to_stream(*stream_, str);
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print_string(std::string_view str, bool allow_multi_line, bool allow_bare)
{
@ -88,7 +109,7 @@ TOML_IMPL_NAMESPACE_START
return;
}
auto multi_line = allow_multi_line && multi_line_strings_allowed();
auto multi_line = allow_multi_line && !!(config_.flags & format_flags::allow_multi_line_strings);
if (multi_line || literals || allow_bare)
{
utf8_decoder decoder;
@ -148,26 +169,49 @@ TOML_IMPL_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<int64_t>& val)
{
if (value_format_flags_allowed() && *val >= 0)
{
static constexpr auto value_format_flags =
value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
const auto fmt = val.flags() & value_format_flags;
if (fmt != value_flags::none)
{
switch (fmt)
{
case value_flags::format_as_binary: print_to_stream(*stream_, "0b"sv); break;
case value_flags::format_as_octal: print_to_stream(*stream_, "0o"sv); break;
case value_flags::format_as_hexadecimal: print_to_stream(*stream_, "0x"sv); break;
default: TOML_UNREACHABLE;
}
}
print_to_stream(*stream_, *val, fmt);
}
else
print_to_stream(*stream_, *val);
naked_newline_ = false;
if (*val >= 0 && !!int_format_mask_)
{
static constexpr auto value_flags_mask =
value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
const auto fmt = val.flags() & value_flags_mask;
switch (fmt)
{
case value_flags::format_as_binary:
if (!!(int_format_mask_ & format_flags::allow_binary_integers))
{
print_to_stream(*stream_, "0b"sv);
print_to_stream(*stream_, *val, fmt);
return;
}
break;
case value_flags::format_as_octal:
if (!!(int_format_mask_ & format_flags::allow_octal_integers))
{
print_to_stream(*stream_, "0o"sv);
print_to_stream(*stream_, *val, fmt);
return;
}
break;
case value_flags::format_as_hexadecimal:
if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers))
{
print_to_stream(*stream_, "0x"sv);
print_to_stream(*stream_, *val, fmt);
return;
}
break;
default: break;
}
}
// fallback to decimal
print_to_stream(*stream_, *val);
}
TOML_EXTERNAL_LINKAGE
@ -176,16 +220,16 @@ TOML_IMPL_NAMESPACE_START
const std::string_view* inf_nan = nullptr;
switch (fpclassify(*val))
{
case fp_class::neg_inf: inf_nan = &constants_->neg_inf; break;
case fp_class::pos_inf: inf_nan = &constants_->pos_inf; break;
case fp_class::nan: inf_nan = &constants_->nan; break;
case fp_class::neg_inf: inf_nan = &constants_->float_neg_inf; break;
case fp_class::pos_inf: inf_nan = &constants_->float_pos_inf; break;
case fp_class::nan: inf_nan = &constants_->float_nan; break;
case fp_class::ok: print_to_stream(*stream_, *val); break;
default: TOML_UNREACHABLE;
}
if (inf_nan)
{
if (quote_infinities_and_nans())
if (!!(config_.flags & format_flags::quote_infinities_and_nans))
print_to_stream_bookended(*stream_, *inf_nan, '"');
else
print_to_stream(*stream_, *inf_nan);
@ -197,14 +241,13 @@ TOML_IMPL_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<bool>& val)
{
print_to_stream(*stream_, *val);
naked_newline_ = false;
print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<date>& val)
{
if (quote_dates_and_times())
if (!!(config_.flags & format_flags::quote_dates_and_times))
print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
else
print_to_stream(*stream_, *val);
@ -214,7 +257,7 @@ TOML_IMPL_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<time>& val)
{
if (quote_dates_and_times())
if (!!(config_.flags & format_flags::quote_dates_and_times))
print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
else
print_to_stream(*stream_, *val);
@ -224,7 +267,7 @@ TOML_IMPL_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<date_time>& val)
{
if (quote_dates_and_times())
if (!!(config_.flags & format_flags::quote_dates_and_times))
print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
else
print_to_stream(*stream_, *val);
@ -275,3 +318,4 @@ TOML_IMPL_NAMESPACE_START
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -102,6 +102,8 @@ TOML_NAMESPACE_START
class toml_formatter;
class json_formatter;
class yaml_formatter;
class xml_formatter;
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
#if TOML_EXCEPTIONS
@ -297,7 +299,7 @@ TOML_NAMESPACE_START // abi namespace
none,
/// \brief Dates and times will be emitted as quoted strings.
quote_dates_and_times = 1ull,
quote_dates_and_times = (1ull << 0),
/// \brief Infinities and NaNs will be emitted as quoted strings.
quote_infinities_and_nans = (1ull << 1),
@ -308,14 +310,20 @@ TOML_NAMESPACE_START // abi namespace
/// \brief Strings containing newlines will be emitted as triple-quoted 'multi-line' strings where possible.
allow_multi_line_strings = (1ull << 3),
/// \brief Values with special format flags will be formatted accordingly.
allow_value_format_flags = (1ull << 4),
/// \brief Allow integers with #value_flags::format_as_binary to be emitted as binary.
allow_binary_integers = (1ull << 4),
/// \brief Allow integers with #value_flags::format_as_octal to be emitted as octal.
allow_octal_integers = (1ull << 5),
/// \brief Allow integers with #value_flags::format_as_hexadecimal to be emitted as hexadecimal.
allow_hexadecimal_integers = (1ull << 6),
/// \brief Apply indentation to tables nested within other tables/arrays.
indent_sub_tables = (1ull << 5),
indent_sub_tables = (1ull << 7),
/// \brief Apply indentation to array elements when the array is forced to wrap over multiple lines.
indent_array_elements = (1ull << 6),
indent_array_elements = (1ull << 8),
/// \brief Combination mask of all indentation-enabling flags.
indentation = indent_sub_tables | indent_array_elements,

View File

@ -5,7 +5,7 @@
#pragma once
#include "preprocessor.h"
#if TOML_ENABLE_JSON_FORMATTER
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "header_start.h"
@ -14,7 +14,7 @@ TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
///
/// \availability This class is only available when #TOML_ENABLE_TOML_FORMATTER is enabled.
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \detail \cpp
/// auto some_toml = toml::parse(R"(
@ -26,7 +26,6 @@ TOML_NAMESPACE_START
/// smooth = true
/// )"sv);
/// std::cout << toml::json_formatter{ some_toml } << "\n";
///
/// \ecpp
///
/// \out
@ -60,16 +59,21 @@ TOML_NAMESPACE_START
TOML_API
void print();
static constexpr impl::formatter_constants constants = { "Infinity"sv, "-Infinity"sv, "NaN"sv };
static constexpr format_flags mandatory_flags = format_flags::quote_dates_and_times;
static constexpr format_flags ignored_flags =
format_flags::allow_literal_strings | format_flags::allow_multi_line_strings;
static constexpr impl::formatter_constants constants = {
format_flags::quote_dates_and_times, // mandatory
format_flags::allow_literal_strings | format_flags::allow_multi_line_strings, // ignored
"Infinity"sv,
"-Infinity"sv,
"NaN"sv,
"true"sv,
"false"sv
};
/// \endcond
public:
/// \brief The default flags for a json_formatter.
static constexpr format_flags default_flags = format_flags::quote_dates_and_times //
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::quote_infinities_and_nans //
| format_flags::indentation;
@ -79,7 +83,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { (flags | mandatory_flags) & ~ignored_flags, " "sv } }
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if defined(DOXYGEN) || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
@ -110,7 +114,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { (flags | mandatory_flags) & ~ignored_flags, " "sv } }
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
@ -134,4 +138,4 @@ TOML_NAMESPACE_START
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_JSON_FORMATTER
#endif // TOML_ENABLE_FORMATTERS

View File

@ -10,7 +10,7 @@
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_JSON_FORMATTER
#if TOML_ENABLE_FORMATTERS
#include "json_formatter.h"
#include "print_to_stream.h"
@ -24,76 +24,78 @@ TOML_NAMESPACE_START
void json_formatter::print(const toml::table& tbl)
{
if (tbl.empty())
impl::print_to_stream(base::stream(), "{}"sv);
else
{
impl::print_to_stream(base::stream(), '{');
if (base::indent_sub_tables())
base::increase_indent();
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
impl::print_to_stream(base::stream(), ',');
first = true;
base::print_newline(true);
base::print_indent();
base::print_unformatted("{}"sv);
return;
}
base::print_string(k, false);
impl::print_to_stream(base::stream(), " : "sv);
base::print_unformatted('{');
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
if (base::indent_sub_tables())
base::decrease_indent();
if (base::indent_sub_tables())
base::increase_indent();
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
base::print_unformatted(',');
first = true;
base::print_newline(true);
base::print_indent();
impl::print_to_stream(base::stream(), '}');
base::print_string(k, false);
base::print_unformatted(" : "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
base::clear_naked_newline();
if (base::indent_sub_tables())
base::decrease_indent();
base::print_newline(true);
base::print_indent();
base::print_unformatted('}');
}
TOML_EXTERNAL_LINKAGE
void json_formatter::print(const toml::array& arr)
{
if (arr.empty())
impl::print_to_stream(base::stream(), "[]"sv);
else
{
impl::print_to_stream(base::stream(), '[');
if (base::indent_array_elements())
base::increase_indent();
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0u)
impl::print_to_stream(base::stream(), ',');
base::print_newline(true);
base::print_indent();
base::print_unformatted("[]"sv);
return;
}
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
if (base::indent_array_elements())
base::decrease_indent();
base::print_unformatted('[');
if (base::indent_array_elements())
base::increase_indent();
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0u)
base::print_unformatted(',');
base::print_newline(true);
base::print_indent();
impl::print_to_stream(base::stream(), ']');
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
base::clear_naked_newline();
if (base::indent_array_elements())
base::decrease_indent();
base::print_newline(true);
base::print_indent();
base::print_unformatted(']');
}
TOML_EXTERNAL_LINKAGE
@ -113,4 +115,4 @@ TOML_NAMESPACE_START
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_JSON_FORMATTER
#endif // TOML_ENABLE_FORMATTERS

View File

@ -718,11 +718,11 @@ TOML_NAMESPACE_START
/// @}
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the viewed node out to a stream.
///
/// \availability This operator is only available when #TOML_ENABLE_TOML_FORMATTER is enabled.
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& os, const node_view& nv)
{
if (nv.node_)

View File

@ -269,7 +269,7 @@ TOML_NAMESPACE_START
///
/// \see toml::node_view
TOML_NODISCARD
node_view<node> operator[](string_view key) noexcept
node_view<node> operator[](std::string_view key) noexcept
{
return err_ ? node_view<node>{} : table()[key];
}
@ -283,7 +283,7 @@ TOML_NAMESPACE_START
///
/// \see toml::node_view
TOML_NODISCARD
node_view<const node> operator[](string_view key) const noexcept
node_view<const node> operator[](std::string_view key) const noexcept
{
return err_ ? node_view<const node>{} : table()[key];
}
@ -372,11 +372,17 @@ TOML_NAMESPACE_START
return err_ ? const_table_iterator{} : table().cend();
}
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the held error or table object out to a text stream.
///
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& os, const parse_result& result)
{
return result.err_ ? (os << result.error()) : (os << result.table());
}
#endif
};
TOML_ABI_NAMESPACE_END;

View File

@ -742,17 +742,13 @@ TOML_ANON_NAMESPACE_START
node_ptr(node_ptr&&) = delete;
node_ptr& operator=(node_ptr&&) = delete;
TOML_NODISCARD
TOML_ATTR(pure)
TOML_ALWAYS_INLINE
TOML_PURE_INLINE_GETTER
operator bool() const noexcept
{
return node_ != nullptr;
}
TOML_NODISCARD
TOML_ATTR(pure)
TOML_ALWAYS_INLINE
TOML_PURE_INLINE_GETTER
node* get() const noexcept
{
return node_;
@ -818,7 +814,7 @@ TOML_ANON_NAMESPACE_END;
// They're all #undef'd at the bottom of the parser's implementation so they should be harmless outside
// of toml++.
#if defined(NDEBUG) || !defined(_DEBUG)
#ifdef NDEBUG
#define assert_or_assume(cond) TOML_ASSUME(cond)
#else
#define assert_or_assume(cond) TOML_ASSERT(cond)
@ -2576,16 +2572,26 @@ TOML_IMPL_NAMESPACE_START
else if (has_any(has_x | has_o | has_b))
{
int64_t i;
value_flags flags;
if (has_any(has_x))
i = parse_integer<16>();
{
i = parse_integer<16>();
flags = value_flags::format_as_hexadecimal;
}
else if (has_any(has_o))
i = parse_integer<8>();
{
i = parse_integer<8>();
flags = value_flags::format_as_octal;
}
else // has_b
i = parse_integer<2>();
{
i = parse_integer<2>();
flags = value_flags::format_as_binary;
}
return_if_error({});
val = new value{ i };
reinterpret_cast<value<int64_t>*>(val.get())->flags(value_flags::format_as_hexadecimal);
reinterpret_cast<value<int64_t>*>(val.get())->flags(flags);
}
else if (has_any(has_e) || (has_any(begins_zero | begins_digit) && chars[1] == U'.'))
val = new value{ parse_float() };

View File

@ -390,20 +390,12 @@
#define TOML_ENABLE_PARSER 1
#endif
// toml formatter
#if !defined(TOML_ENABLE_TOML_FORMATTER) \
|| (defined(TOML_ENABLE_TOML_FORMATTER) && TOML_ENABLE_TOML_FORMATTER) \
// formatters
#if !defined(TOML_ENABLE_FORMATTERS) \
|| (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) \
|| TOML_INTELLISENSE
#undef TOML_ENABLE_TOML_FORMATTER
#define TOML_ENABLE_TOML_FORMATTER 1
#endif
// json formatter
#if !defined(TOML_ENABLE_JSON_FORMATTER) \
|| (defined(TOML_ENABLE_JSON_FORMATTER) && TOML_ENABLE_JSON_FORMATTER) \
|| TOML_INTELLISENSE
#undef TOML_ENABLE_JSON_FORMATTER
#define TOML_ENABLE_JSON_FORMATTER 1
#undef TOML_ENABLE_FORMATTERS
#define TOML_ENABLE_FORMATTERS 1
#endif
// windows compat
@ -691,23 +683,17 @@
#define TOML_EXTERN_NOEXCEPT(...) noexcept(__VA_ARGS__)
#endif
#define TOML_PURE_GETTER \
TOML_NODISCARD \
TOML_ATTR(pure)
#define TOML_PURE_INLINE_GETTER \
TOML_NODISCARD \
TOML_ALWAYS_INLINE \
TOML_ATTR(pure)
#define TOML_CONST_GETTER \
TOML_NODISCARD \
TOML_ATTR(const)
#define TOML_CONST_INLINE_GETTER \
TOML_NODISCARD \
TOML_ALWAYS_INLINE \
TOML_ATTR(const)
#ifdef NDEBUG
#define TOML_PURE_GETTER TOML_NODISCARD TOML_ATTR(pure)
#define TOML_CONST_GETTER TOML_NODISCARD TOML_ATTR(const)
#define TOML_PURE_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE TOML_ATTR(pure)
#define TOML_CONST_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE TOML_ATTR(const)
#else
#define TOML_PURE_GETTER TOML_NODISCARD
#define TOML_CONST_GETTER TOML_NODISCARD
#define TOML_PURE_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE
#define TOML_CONST_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE
#endif
//======================================================================================================================
// SFINAE
@ -721,10 +707,16 @@
#endif
#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0
#define TOML_CONSTRAINED_TEMPLATE(condition, ...) template <__VA_ARGS__ TOML_ENABLE_IF(condition)> TOML_REQUIRES(condition)
#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__)
/// \endcond
//# {{
#ifndef TOML_CONSTRAINED_TEMPLATE
#define TOML_CONSTRAINED_TEMPLATE(condition, ...) template <__VA_ARGS__>
#endif
#ifndef TOML_HIDDEN_CONSTRAINT
#define TOML_HIDDEN_CONSTRAINT(condition, ...)
#endif
//# }}
//#====================================================================================================================
//# EXTENDED INT AND FLOAT TYPES
@ -833,7 +825,7 @@
TOML_DISABLE_WARNINGS;
#ifndef TOML_ASSERT
#if defined(NDEBUG) || !defined(_DEBUG)
#ifdef NDEBUG
#define TOML_ASSERT(expr) static_cast<void>(0)
#else
#ifndef assert
@ -976,17 +968,15 @@ TOML_ENABLE_WARNINGS;
/// to `0` can improve compilation speed and reduce binary size.
/// \def TOML_ENABLE_TOML_FORMATTER
/// \brief Sets whether the #toml::toml_formatter is enabled.
/// \def TOML_ENABLE_FORMATTERS
/// \brief Sets whether the various formatter classes are enabled.
/// \detail Defaults to `1`.
/// \remarks If you don't need to re-serialize TOML data, setting `TOML_ENABLE_TOML_FORMATTER`
/// to `0` can improve compilation speed and reduce binary size.
/// \def TOML_ENABLE_JSON_FORMATTER
/// \brief Sets whether the #toml::json_formatter is enabled.
/// \detail Defaults to `1`.
/// \remarks If you don't need to re-serialize TOML data as JSON, setting `TOML_ENABLE_JSON_FORMATTER`
/// \remarks If you don't need to re-serialize TOML data, setting `TOML_ENABLE_FORMATTERS`
/// to `0` can improve compilation speed and reduce binary size.
/// \see
/// - toml::toml_formatter
/// - toml::json_formatter
/// - toml::yaml_formatter
#define TOML_SMALL_FLOAT_TYPE

View File

@ -80,7 +80,7 @@ TOML_IMPL_NAMESPACE_START
TOML_API
void print_to_stream(std::ostream&, const source_region&);
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
TOML_API
void print_to_stream(std::ostream&, const array&);

View File

@ -77,6 +77,10 @@ TOML_ANON_NAMESPACE_START
return;
}
static constexpr auto value_flags_mask =
value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
format &= value_flags_mask;
int base = 10;
if (format != value_flags::none && val >= T{})
{
@ -403,7 +407,7 @@ TOML_IMPL_NAMESPACE_START
}
}
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const array& arr)

View File

@ -24,11 +24,6 @@ namespace toml // non-abi namespace; this is not an error
{
using namespace std::string_literals;
using namespace std::string_view_literals;
// legacy typedefs
using string_char = char;
using string = std::string;
using string_view = std::string_view;
}
#if TOML_ENABLE_WINDOWS_COMPAT

View File

@ -1516,11 +1516,11 @@ TOML_NAMESPACE_START
/// @}
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the table out to a stream as formatted TOML.
///
/// \availability This operator is only available when #TOML_ENABLE_TOML_FORMATTER is enabled.
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& lhs, const table& rhs)
{
impl::print_to_stream(lhs, rhs);

View File

@ -5,7 +5,7 @@
#pragma once
#include "preprocessor.h"
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "std_vector.h"
@ -15,7 +15,7 @@ TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
///
/// \availability This class is only available when #TOML_ENABLE_TOML_FORMATTER is enabled.
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \remarks You generally don't need to create an instance of this class explicitly; the stream
/// operators of the TOML node types already print themselves out using this formatter.
@ -31,7 +31,6 @@ TOML_NAMESPACE_START
/// // these two lines are equivalent:
/// std::cout << toml::toml_formatter{ tbl } << "\n";
/// std::cout << tbl << "\n";
///
/// \ecpp
///
/// \out
@ -51,16 +50,6 @@ TOML_NAMESPACE_START
std::vector<std::string_view> key_path_;
bool pending_table_separator_ = false;
static constexpr size_t line_wrap_cols = 120;
TOML_NODISCARD
TOML_API
static size_t count_inline_columns(const node&) noexcept;
TOML_NODISCARD
TOML_API
static bool forces_multiline(const node&, size_t = 0) noexcept;
TOML_API
void print_pending_table_separator();
@ -82,17 +71,24 @@ TOML_NAMESPACE_START
TOML_API
void print();
static constexpr impl::formatter_constants constants = { "inf"sv, "-inf"sv, "nan"sv };
static constexpr format_flags mandatory_flags = format_flags::none;
static constexpr format_flags ignored_flags = format_flags::none;
static constexpr impl::formatter_constants constants = { format_flags::none, // mandatory flags
format_flags::none, // ignored flags
"inf"sv,
"-inf"sv,
"nan"sv,
"true"sv,
"false"sv };
/// \endcond
public:
/// \brief The default flags for a toml_formatter.
static constexpr format_flags default_flags = format_flags::allow_literal_strings //
| format_flags::allow_multi_line_strings //
| format_flags::allow_value_format_flags //
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::allow_literal_strings //
| format_flags::allow_multi_line_strings //
| format_flags::allow_binary_integers //
| format_flags::allow_octal_integers //
| format_flags::allow_hexadecimal_integers //
| format_flags::indentation;
/// \brief Constructs a TOML formatter and binds it to a TOML object.
@ -101,7 +97,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit toml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { (flags | mandatory_flags) & ~ignored_flags, " "sv } }
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if defined(DOXYGEN) || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
@ -130,7 +126,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit toml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { (flags | mandatory_flags) & ~ignored_flags, " "sv } }
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
@ -155,4 +151,4 @@ TOML_NAMESPACE_START
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_TOML_FORMATTER
#endif // TOML_ENABLE_FORMATTERS

View File

@ -10,7 +10,7 @@
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
#include "toml_formatter.h"
#include "print_to_stream.h"
@ -21,10 +21,10 @@
#include "header_start.h"
TOML_DISABLE_ARITHMETIC_WARNINGS;
TOML_NAMESPACE_START
TOML_ANON_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
size_t toml_formatter::count_inline_columns(const node& node) noexcept
TOML_INTERNAL_LINKAGE
size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept
{
switch (node.type())
{
@ -36,7 +36,7 @@ TOML_NAMESPACE_START
size_t weight = 3u; // "{ }"
for (auto&& [k, v] : tbl)
{
weight += k.length() + count_inline_columns(v) + 2u; // + ", "
weight += k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // + ", "
if (weight >= line_wrap_cols)
break;
}
@ -51,7 +51,7 @@ TOML_NAMESPACE_START
size_t weight = 3u; // "[ ]"
for (auto& elem : arr)
{
weight += count_inline_columns(elem) + 2u; // + ", "
weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // + ", "
if (weight >= line_wrap_cols)
break;
}
@ -106,12 +106,16 @@ TOML_NAMESPACE_START
TOML_UNREACHABLE;
}
TOML_EXTERNAL_LINKAGE
bool toml_formatter::forces_multiline(const node& node, size_t starting_column_bias) noexcept
TOML_INTERNAL_LINKAGE
bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols, size_t starting_column_bias) noexcept
{
return (count_inline_columns(node) + starting_column_bias) >= line_wrap_cols;
return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >= line_wrap_cols;
}
}
TOML_ANON_NAMESPACE_END;
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
void toml_formatter::print_pending_table_separator()
{
@ -135,104 +139,107 @@ TOML_NAMESPACE_START
for (const auto& segment : key_path_)
{
if (std::addressof(segment) > key_path_.data())
impl::print_to_stream(base::stream(), '.');
base::print_unformatted('.');
print_key_segment(segment);
}
base::clear_naked_newline();
}
TOML_EXTERNAL_LINKAGE
void toml_formatter::print_inline(const table& tbl)
{
if (tbl.empty())
impl::print_to_stream(base::stream(), "{}"sv);
else
{
impl::print_to_stream(base::stream(), "{ "sv);
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
impl::print_to_stream(base::stream(), ", "sv);
first = true;
print_key_segment(k);
impl::print_to_stream(base::stream(), " = "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
impl::print_to_stream(base::stream(), " }"sv);
base::print_unformatted("{}"sv);
return;
}
base::clear_naked_newline();
base::print_unformatted("{ "sv);
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
base::print_unformatted(", "sv);
first = true;
print_key_segment(k);
base::print_unformatted(" = "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
base::print_unformatted(" }"sv);
}
TOML_EXTERNAL_LINKAGE
void toml_formatter::print(const array& arr)
{
if (arr.empty())
impl::print_to_stream(base::stream(), "[]"sv);
else
{
const auto original_indent = base::indent();
const auto multiline = forces_multiline(
arr,
base::indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
impl::print_to_stream(base::stream(), "["sv);
base::print_unformatted("[]"sv);
return;
}
const auto original_indent = base::indent();
const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
arr,
120u,
base::indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
base::print_unformatted("["sv);
if (multiline)
{
if (original_indent < 0)
base::indent(0);
if (base::indent_array_elements())
base::increase_indent();
}
else
base::print_unformatted(' ');
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0u)
{
base::print_unformatted(',');
if (!multiline)
base::print_unformatted(' ');
}
if (multiline)
{
if (original_indent < 0)
base::indent(0);
if (base::indent_array_elements())
base::increase_indent();
}
else
impl::print_to_stream(base::stream(), ' ');
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0u)
{
impl::print_to_stream(base::stream(), ',');
if (!multiline)
impl::print_to_stream(base::stream(), ' ');
}
if (multiline)
{
base::print_newline(true);
base::print_indent();
}
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
if (multiline)
{
base::indent(original_indent);
base::print_newline(true);
base::print_indent();
}
else
impl::print_to_stream(base::stream(), ' ');
impl::print_to_stream(base::stream(), "]"sv);
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
base::clear_naked_newline();
if (multiline)
{
base::indent(original_indent);
base::print_newline(true);
base::print_indent();
}
else
base::print_unformatted(' ');
base::print_unformatted("]"sv);
}
TOML_EXTERNAL_LINKAGE
@ -256,7 +263,7 @@ TOML_NAMESPACE_START
base::print_newline();
base::print_indent();
print_key_segment(k);
impl::print_to_stream(base::stream(), " = "sv);
base::print_unformatted(" = "sv);
TOML_ASSUME(type != node_type::none);
switch (type)
{
@ -315,9 +322,9 @@ TOML_NAMESPACE_START
if (base::indent_sub_tables())
base::increase_indent();
base::print_indent();
impl::print_to_stream(base::stream(), "["sv);
base::print_unformatted("["sv);
print_key_path();
impl::print_to_stream(base::stream(), "]"sv);
base::print_unformatted("]"sv);
pending_table_separator_ = true;
}
@ -343,9 +350,9 @@ TOML_NAMESPACE_START
{
print_pending_table_separator();
base::print_indent();
impl::print_to_stream(base::stream(), "[["sv);
base::print_unformatted("[["sv);
print_key_path();
impl::print_to_stream(base::stream(), "]]"sv);
base::print_unformatted("]]"sv);
pending_table_separator_ = true;
print(*reinterpret_cast<const table*>(&arr[i]));
}
@ -386,4 +393,4 @@ TOML_NAMESPACE_START
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_TOML_FORMATTER
#endif // TOML_ENABLE_FORMATTERS

View File

@ -2,12 +2,12 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
#include "header_start.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
TOML_CONST_GETTER
@ -935,6 +935,6 @@ TOML_IMPL_NAMESPACE_START
};
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
/// \endcond
#include "header_end.h"

View File

@ -154,8 +154,7 @@ TOML_IMPL_NAMESPACE_START
#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
template <typename T>
TOML_NODISCARD
TOML_ATTR(const)
TOML_CONST_GETTER
inline optional<T> node_integer_cast(int64_t val) noexcept
{
static_assert(node_type_of<T> == node_type::integer);
@ -595,68 +594,88 @@ TOML_NAMESPACE_START
/// @{
/// \brief Returns a reference to the underlying value.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type& get() & noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (rvalue overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type&& get() && noexcept
{
return static_cast<value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value (const overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
const value_type& get() const& noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type& operator*() & noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (rvalue overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type&& operator*() && noexcept
{
return static_cast<value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value (const overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
const value_type& operator*() const& noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
explicit operator value_type&() & noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (rvalue overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
explicit operator value_type&&() && noexcept
{
return static_cast<value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value (const overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
explicit operator const value_type&() const& noexcept
{
return val_;
}
/// \brief Returns a pointer to the underlying value.
///
/// \availability This operator is only available when #value_type is a class/struct.
TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
TOML_PURE_INLINE_GETTER
value_type* operator->() noexcept
{
return &val_;
}
/// \brief Returns a pointer to the underlying value (const overload).
///
/// \availability This operator is only available when #value_type is a class/struct.
TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
TOML_PURE_INLINE_GETTER
const value_type* operator->() const noexcept
{
return &val_;
}
/// @}
/// \name Metadata
@ -879,11 +898,11 @@ TOML_NAMESPACE_START
/// @}
#if TOML_ENABLE_TOML_FORMATTER
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the value out to a stream as formatted TOML.
///
/// \availability This operator is only available when #TOML_ENABLE_TOML_FORMATTER is enabled.
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& lhs, const value& rhs)
{
impl::print_to_stream(lhs, rhs);

View File

@ -0,0 +1,138 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted YAML.
///
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \detail \cpp
/// auto some_toml = toml::parse(R"(
/// [fruit]
/// apple.color = "red"
/// apple.taste.sweet = true
///
/// [fruit.apple.texture]
/// smooth = true
/// )"sv);
/// std::cout << toml::yaml_formatter{ some_toml } << "\n";
/// \ecpp
///
/// \out
/// fruit:
/// apple:
/// color: red
/// taste:
/// sweet: true
/// texture:
/// smooth: true
/// \eout
class yaml_formatter : impl::formatter
{
private:
/// \cond
using base = impl::formatter;
TOML_API
void print_yaml_string(const value<std::string>&);
TOML_API
void print(const toml::table&, bool = false);
TOML_API
void print(const toml::array&, bool = false);
TOML_API
void print();
static constexpr impl::formatter_constants constants = {
//
format_flags::quote_dates_and_times | format_flags::indentation, // mandatory
format_flags::allow_multi_line_strings, // ignored
".inf"sv,
"-.inf"sv,
".NAN"sv,
"true"sv,
"false"sv
};
/// \endcond
public:
/// \brief The default flags for a yaml_formatter.
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::allow_literal_strings //
| format_flags::allow_octal_integers //
| format_flags::allow_hexadecimal_integers;
/// \brief Constructs a YAML formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit yaml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if defined(DOXYGEN) || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a YAML formatter and binds it to a toml::parse_result.
///
/// \availability This constructor is only available when exceptions are disabled.
///
/// \attention Formatting a failed parse result will simply dump the error message out as-is.
/// This will not be valid YAML, but at least gives you something to log or show up in diagnostics:
/// \cpp
/// std::cout << toml::yaml_formatter{ toml::parse("a = 'b'"sv) } // ok
/// << "\n\n"
/// << toml::yaml_formatter{ toml::parse("a = "sv) } // malformed
/// << "\n";
/// \ecpp
/// \out
/// a: b
///
/// Error while parsing key-value pair: encountered end-of-file
/// (error occurred at line 1, column 5)
/// \eout
/// Use the library with exceptions if you want to avoid this scenario.
///
/// \param result The parse result.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit yaml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
/// \brief Prints the bound TOML object out to the stream as YAML.
friend std::ostream& operator<<(std::ostream& lhs, yaml_formatter& rhs)
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as YAML (rvalue overload).
friend std::ostream& operator<<(std::ostream& lhs, yaml_formatter&& rhs)
{
return lhs << rhs; // as lvalue
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,166 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "yaml_formatter.h"
#include "print_to_stream.h"
#include "table.h"
#include "array.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print_yaml_string(const value<std::string>& str)
{
if (str->empty())
{
base::print(str);
return;
}
bool contains_newline = false;
for (auto c = str->c_str(), e = str->c_str() + str->length(); c < e && !contains_newline; c++)
contains_newline = *c == '\n';
if (contains_newline)
{
base::print_unformatted("|-"sv);
base::increase_indent();
auto line_end = str->c_str() - 1u;
const auto end = str->c_str() + str->length();
while (line_end != end)
{
auto line_start = line_end + 1u;
line_end = line_start;
for (; line_end != end && *line_end != '\n'; line_end++)
;
if TOML_LIKELY(line_start != line_end || line_end != end)
{
base::print_newline();
base::print_indent();
base::print_unformatted(std::string_view{ line_start, static_cast<size_t>(line_end - line_start) });
}
}
base::decrease_indent();
}
else
base::print_string(*str, false, true);
}
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print(const toml::table& tbl, bool parent_is_array)
{
if (tbl.empty())
{
base::print_unformatted("{}"sv);
return;
}
base::increase_indent();
for (auto&& [k, v] : tbl)
{
if (!parent_is_array)
{
base::print_newline();
base::print_indent();
}
parent_is_array = false;
base::print_string(k, false, true);
base::print_unformatted(": "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
default: base::print_value(v, type);
}
}
base::decrease_indent();
}
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print(const toml::array& arr, bool parent_is_array)
{
if (arr.empty())
{
base::print_unformatted("[]"sv);
return;
}
base::increase_indent();
for (auto&& v : arr)
{
if (!parent_is_array)
{
base::print_newline();
base::print_indent();
}
parent_is_array = false;
base::print_unformatted("- "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v), true); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v), true); break;
case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
default: base::print_value(v, type);
}
base::print_newline();
}
base::decrease_indent();
}
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print()
{
if (base::dump_failed_parse_result())
return;
switch (auto source_type = base::source().type())
{
case node_type::table:
base::decrease_indent(); // so root kvps and tables have the same indent
print(*reinterpret_cast<const table*>(&base::source()));
break;
case node_type::array: print(*reinterpret_cast<const array*>(&base::source())); break;
case node_type::string:
print_yaml_string(*reinterpret_cast<const value<std::string>*>(&base::source()));
break;
default: base::print_value(base::source(), source_type);
}
}
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -41,6 +41,7 @@ TOML_DISABLE_SWITCH_WARNINGS;
#include "impl/formatter.h"
#include "impl/toml_formatter.h"
#include "impl/json_formatter.h"
#include "impl/yaml_formatter.h"
#if TOML_IMPLEMENTATION
@ -55,6 +56,7 @@ TOML_DISABLE_SWITCH_WARNINGS;
#include "impl/formatter.inl"
#include "impl/toml_formatter.inl"
#include "impl/json_formatter.inl"
#include "impl/yaml_formatter.inl"
#endif // TOML_IMPLEMENTATION
@ -107,6 +109,7 @@ TOML_POP_WARNINGS;
#undef TOML_HAS_CHAR8
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
#undef TOML_HAS_INCLUDE
#undef TOML_HIDDEN_CONSTRAINT
#undef TOML_ICC
#undef TOML_ICC_CL
#undef TOML_IMPL_NAMESPACE_END

View File

@ -122,14 +122,14 @@ if is_gcc
'-Wvariadic-macros',
'-Wwrite-strings',
'-Wmissing-noreturn',
'-Wsuggest-attribute=const',
'-Wsuggest-attribute=pure',
language: 'cpp'
)
endif
if is_release
add_project_arguments(
'-fmerge-constants',
'-Wsuggest-attribute=const',
'-Wsuggest-attribute=pure',
language: 'cpp'
)
endif

View File

@ -102,55 +102,59 @@ namespace
TEST_CASE("formatters")
{
const auto data = toml::table{
{ "integers"sv,
toml::table{ { "zero"sv, 0 },
{ "one"sv, 1 },
{ "dec"sv, 10 },
{ "bin"sv, 10, toml::value_flags::format_as_binary },
{ "oct"sv, 10, toml::value_flags::format_as_octal },
{ "hex"sv, 10, toml::value_flags::format_as_hexadecimal } } },
{ "floats"sv,
toml::table{ { "pos_zero"sv, +0.0 },
{ "neg_zero"sv, -0.0 },
{ "one"sv, 1.0 },
{ "pos_inf"sv, +std::numeric_limits<double>::infinity() },
{ "neg_inf"sv, -std::numeric_limits<double>::infinity() },
{ "pos_nan"sv, +std::numeric_limits<double>::quiet_NaN() },
{ "neg_nan"sv, -std::numeric_limits<double>::quiet_NaN() }
const auto data_date = toml::date{ 2021, 11, 2 };
const auto data_time = toml::time{ 20, 33, 0 };
const auto data = toml::table{
{ "integers"sv,
toml::table{ { "zero"sv, 0 },
{ "one"sv, 1 },
{ "dec"sv, 10 },
{ "bin"sv, 10, toml::value_flags::format_as_binary },
{ "oct"sv, 10, toml::value_flags::format_as_octal },
{ "hex"sv, 10, toml::value_flags::format_as_hexadecimal } } },
{ "floats"sv,
toml::table{ { "pos_zero"sv, +0.0 },
{ "neg_zero"sv, -0.0 },
{ "one"sv, 1.0 },
{ "pos_inf"sv, +std::numeric_limits<double>::infinity() },
{ "neg_inf"sv, -std::numeric_limits<double>::infinity() },
{ "pos_nan"sv, +std::numeric_limits<double>::quiet_NaN() },
{ "neg_nan"sv, -std::numeric_limits<double>::quiet_NaN() }
} },
} },
{ "dates and times"sv,
toml::table{
{ "dates and times"sv,
toml::table{
{ "dates"sv, toml::table{ { "zero"sv, toml::date{} } } },
{ "dates"sv, toml::table{ { "val"sv, data_date } } },
{ "times"sv, toml::table{ { "zero"sv, toml::time{} } } },
{ "times"sv, toml::table{ { "val"sv, data_time } } },
{ "date-times"sv,
toml::table{
{ "date-times"sv,
toml::table{
{ "local"sv, toml::table{ { "zero"sv, toml::date_time{} } } },
{ "offset"sv, toml::table{ { "zero"sv, toml::date_time{ {}, {}, toml::time_offset{} } } } } } } } },
{ "local"sv, toml::table{ { "val"sv, toml::date_time{ data_date, data_time } } } },
{ "offset"sv,
toml::table{
{ "val"sv, toml::date_time{ data_date, data_time, toml::time_offset{} } } } } } } } },
{ "bools"sv,
toml::table{ { "true"sv, true }, //
{ "false"sv, false } } },
{ "bools"sv,
toml::table{ { "true"sv, true }, //
{ "false"sv, false } } },
{
"strings"sv,
toml::array{ R"()"sv,
R"(string)"sv,
R"(string with a single quote in it: ')"sv,
R"(string with a double quote in it: ")"sv,
"string with a tab: \t"sv,
R"(a long string to force the array over multiple lines)"sv },
},
{
"strings"sv,
toml::array{ R"()"sv,
R"(string)"sv,
R"(string with a single quote in it: ')"sv,
R"(string with a double quote in it: ")"sv,
"string with a tab: \t"sv,
R"(a long string to force the array over multiple lines)"sv },
},
{ "a"sv,
toml::table{ { "val", true },
{ "b"sv, toml::table{ { "val", true }, { "c"sv, toml::table{ { "val", true } } } } } } }
{ "a"sv,
toml::table{ { "val", true },
{ "b"sv, toml::table{ { "val", true }, { "c"sv, toml::table{ { "val", true } } } } } } }
};
@ -180,16 +184,16 @@ false = false
true = true
['dates and times'.date-times.local]
zero = 0000-00-00T00:00:00
val = 2021-11-02T20:33:00
['dates and times'.date-times.offset]
zero = 0000-00-00T00:00:00Z
val = 2021-11-02T20:33:00Z
['dates and times'.dates]
zero = 0000-00-00
val = 2021-11-02
['dates and times'.times]
zero = 00:00:00
val = 20:33:00
[floats]
neg_inf = -inf
@ -232,17 +236,17 @@ zero = 0
"dates and times" : {
"date-times" : {
"local" : {
"zero" : "0000-00-00T00:00:00"
"val" : "2021-11-02T20:33:00"
},
"offset" : {
"zero" : "0000-00-00T00:00:00Z"
"val" : "2021-11-02T20:33:00Z"
}
},
"dates" : {
"zero" : "0000-00-00"
"val" : "2021-11-02"
},
"times" : {
"zero" : "00:00:00"
"val" : "20:33:00"
}
},
"floats" : {

View File

@ -75,6 +75,7 @@
<ClInclude Include="include\toml++\impl\value_extern.inl" />
<ClInclude Include="include\toml++\impl\version.h" />
<ClInclude Include="include\toml++\impl\std_string.inl" />
<ClInclude Include="include\toml++\impl\yaml_formatter.h" />
<ClInclude Include="include\toml++\toml.h" />
</ItemGroup>
<ItemGroup>
@ -91,6 +92,7 @@
<None Include="CODE_OF_CONDUCT.md" />
<None Include="CONTRIBUTING.md" />
<None Include="include\toml++\impl\node_view_extern.inl" />
<None Include="include\toml++\impl\yaml_formatter.inl" />
<None Include="LICENSE" />
<None Include="README.md" />
<None Include="cmake\install-rules.cmake" />

View File

@ -124,6 +124,9 @@
<ClInclude Include="include\toml++\impl\value_extern.inl">
<Filter>include\impl</Filter>
</ClInclude>
<ClInclude Include="include\toml++\impl\yaml_formatter.h">
<Filter>include\impl</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="toml++.props" />
@ -195,6 +198,9 @@
<None Include=".github\ISSUE_TEMPLATE\feature_request.md">
<Filter>.github</Filter>
</None>
<None Include="include\toml++\impl\yaml_formatter.inl">
<Filter>include\impl</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Filter Include=".circleci">

911
toml.hpp

File diff suppressed because it is too large Load Diff

View File

@ -203,8 +203,7 @@ def main():
r'TOML_MAX_NESTED_VALUES',
r'TOML_OPTIONAL_TYPE',
r'TOML_ENABLE_PARSER',
r'TOML_ENABLE_TOML_FORMATTER',
r'TOML_ENABLE_JSON_FORMATTER',
r'TOML_ENABLE_FORMATTERS',
r'TOML_SMALL_FLOAT_TYPE',
r'TOML_SMALL_INT_TYPE',
r'TOML_UNDEF_MACROS',