release v3.0.0

This commit is contained in:
Mark Gillard 2022-01-11 18:22:31 +02:00
parent e37e6d2bce
commit d33da0c7a1
11 changed files with 192 additions and 143 deletions

View File

@ -3,7 +3,7 @@
<!--
template:
## [vX.X.X](https://github.com/osgenic/stim/releases/tag/vX.X.X) - YYYY-MM-DD
## [vX.X.X](https://github.com/marzer/tomlplusplus/releases/tag/vX.X.X) - YYYY-MM-DD
#### Fixes:
#### Additions:
@ -15,7 +15,8 @@ template:
## Unreleased
## [v3.0.0](https://github.com/marzer/tomlplusplus/releases/tag/v3.0.0) - 2022-01-11
This release will be a major version bump, so it's ABI breaks all around.
Any changes that are likely to cause migration issues (API changes, build system breakage, etc.) are indicated with ⚠&#xFE0F;.
@ -104,7 +105,7 @@ Any changes that are likely to cause migration issues (API changes, build system
## [v2.5.0](https://github.com/osgenic/stim/releases/tag/v2.5.0) - 2021-07-11
## [v2.5.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.5.0) - 2021-07-11
#### Fixes:
- fixed linkage error with windows compat mode
@ -125,7 +126,7 @@ Any changes that are likely to cause migration issues (API changes, build system
## [v2.4.0](https://github.com/osgenic/stim/releases/tag/v2.4.0) - 2021-05-19
## [v2.4.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.4.0) - 2021-05-19
#### Fixes:
- fixed `node::value()` not retrieving inf and nan correctly
@ -153,7 +154,7 @@ Any changes that are likely to cause migration issues (API changes, build system
## [v2.3.0](https://github.com/osgenic/stim/releases/tag/v2.3.0) - 2020-12-29
## [v2.3.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.3.0) - 2020-12-29
#### Fixes:
- fixed compiler errors caused by `<charconv>` with Apple-flavoured clang
@ -169,7 +170,7 @@ Any changes that are likely to cause migration issues (API changes, build system
## [v2.2.0](https://github.com/osgenic/stim/releases/tag/v2.2.0) - 2020-08-09
## [v2.2.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.2.0) - 2020-08-09
#### Fixes:
- fixed some issues building with VS2017 (#55) (@sobczyk)
@ -197,7 +198,7 @@ Any changes that are likely to cause migration issues (API changes, build system
## [v2.1.0](https://github.com/osgenic/stim/releases/tag/v2.1.0) - 2020-07-11
## [v2.1.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.1.0) - 2020-07-11
#### Fixes:
- fixed inconsistent emission of leading/trailing newlines when writing a table to an ostream (#48) (@levicki)
@ -224,7 +225,7 @@ Any changes that are likely to cause migration issues (API changes, build system
## [v2.0.0](https://github.com/osgenic/stim/releases/tag/v2.0.0) - 2020-07-20
## [v2.0.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.0.0) - 2020-07-20
This release contains a fairly significant number of 'quality of life' improvements, yay! But also necessitates an ABI
break (hence the version number bump). Changes that might block a migration are annotated with ⚠&#xFE0F;.
@ -267,7 +268,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.3.3](https://github.com/osgenic/stim/releases/tag/v1.3.3) - 2020-06-29
## [v1.3.3](https://github.com/marzer/tomlplusplus/releases/tag/v1.3.3) - 2020-06-29
#### Fixes:
- fixed some minor TOML spec conformance bugs
@ -287,7 +288,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.3.2](https://github.com/osgenic/stim/releases/tag/v1.3.2) - 2020-06-19
## [v1.3.2](https://github.com/marzer/tomlplusplus/releases/tag/v1.3.2) - 2020-06-19
#### Fixes:
- fixed single-digit negative integers parsing as positive
@ -301,7 +302,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.3.0](https://github.com/osgenic/stim/releases/tag/v1.3.0) - 2020-06-02
## [v1.3.0](https://github.com/marzer/tomlplusplus/releases/tag/v1.3.0) - 2020-06-02
#### Fixes:
- fixed `formatter::print_inline()` causing compilation failures in DLL builds
@ -320,7 +321,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.2.5](https://github.com/osgenic/stim/releases/tag/v1.2.5) - 2020-04-24
## [v1.2.5](https://github.com/marzer/tomlplusplus/releases/tag/v1.2.5) - 2020-04-24
#### Fixes:
- fixed some multi-line string parsing issues
@ -339,7 +340,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.2.3](https://github.com/osgenic/stim/releases/tag/v1.2.3) - 2020-04-11
## [v1.2.3](https://github.com/marzer/tomlplusplus/releases/tag/v1.2.3) - 2020-04-11
#### Fixes:
- fixed printing of inf and nan
@ -360,7 +361,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.2.0](https://github.com/osgenic/stim/releases/tag/v1.2.0) - 2020-04-07
## [v1.2.0](https://github.com/marzer/tomlplusplus/releases/tag/v1.2.0) - 2020-04-07
#### Fixes:
- fixed some parsing and printing ops being locale-dependent
@ -377,7 +378,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.1.0](https://github.com/osgenic/stim/releases/tag/v1.1.0) - 2020-04-03
## [v1.1.0](https://github.com/marzer/tomlplusplus/releases/tag/v1.1.0) - 2020-04-03
#### Fixes:
- fixed some parser error paths not returning early enough `TOML_EXCEPTIONS=0`
@ -394,7 +395,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v1.0.0](https://github.com/osgenic/stim/releases/tag/1.0.0) - 2020-03-28
## [v1.0.0](https://github.com/marzer/tomlplusplus/releases/tag/1.0.0) - 2020-03-28
#### Fixes:
- fixed minor documentation issues
@ -404,7 +405,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.6.0](https://github.com/osgenic/stim/releases/tag/v0.6.0) - 2020-03-24
## [v0.6.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.6.0) - 2020-03-24
#### Fixes:
- fixed minor preprocessor/macro issues
@ -416,7 +417,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.5.0](https://github.com/osgenic/stim/releases/tag/v0.5.0) - 2020-03-18
## [v0.5.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.5.0) - 2020-03-18
#### Fixes:
- fixed crash when reaching EOF while parsing a string when exceptions are disabled
@ -434,7 +435,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.4.3](https://github.com/osgenic/stim/releases/tag/v0.4.3) - 2020-03-10
## [v0.4.3](https://github.com/marzer/tomlplusplus/releases/tag/v0.4.3) - 2020-03-10
#### Fixes:
- fixed ICE in VS2019 when using `/std:c++17` instead of `/std:c++latest
@ -447,7 +448,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.4.0](https://github.com/osgenic/stim/releases/tag/v0.4.0) - 2020-03-05
## [v0.4.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.4.0) - 2020-03-05
#### Fixes:
- fixed `parse_file()` failing to compile with plain string literals
@ -461,7 +462,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.3.0](https://github.com/osgenic/stim/releases/tag/v0.3.0) - 2020-03-01
## [v0.3.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.3.0) - 2020-03-01
#### Fixes:
- fixed some pedantic clang warnings
@ -479,7 +480,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.2.1](https://github.com/osgenic/stim/releases/tag/v0.2.1) - 2020-02-26
## [v0.2.1](https://github.com/marzer/tomlplusplus/releases/tag/v0.2.1) - 2020-02-26
#### Fixes:
- fixed minor printing bug in `operator<<(ostream, source_position)`
@ -493,7 +494,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.2.0](https://github.com/osgenic/stim/releases/tag/v0.2.0) - 2020-02-23
## [v0.2.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.2.0) - 2020-02-23
#### Fixes:
- fixed truncation of floating-point values when using ostreams
@ -510,7 +511,7 @@ break (hence the version number bump). Changes that might block a migration are
## [v0.1.0](https://github.com/osgenic/stim/releases/tag/v0.1.0) - 2020-02-20
## [v0.1.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.1.0) - 2020-02-20
- First public release, yay! 🎉&#xFE0F;

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -260,6 +260,10 @@
std::cout << "cats: " << tbl["animals"]["cats"] << "\n";
std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n";
// can also be retrieved via absolute path
std::cout << "cats: " << tbl.at_path("animals.cats") << "\n";
std::cout << "fish[1]: " << tbl.at_path("animals.fish[1]") << "\n";
// ...even if the element doesn't exist
std::cout << "dinosaurs: " << tbl["animals"]["dinosaurs"] << "\n"; //no dinosaurs :(
@ -278,6 +282,8 @@
numbers: [ 2, 3, 4, 'five', 6.0, 7, [ 8, 9 ] ]
cats: [ 'tiger', 'lion', 'puma' ]
fish[1]: 'trout'
cats: [ 'tiger', 'lion', 'puma' ]
fish[1]: 'trout'
dinosaurs:
\eout
@ -514,10 +520,12 @@
\out
Parsing data.toml 5000 times:
pytomlpp: 0.662 s
toml: 5.277 s (7.9x slower)
qtoml: 8.020 s (12.1x slower)
tomlkit: 32.898 s (49.6x slower)
pytomlpp: 0.694 s
rtoml: 0.871 s ( 1.25x)
tomli: 2.625 s ( 3.78x)
toml: 5.642 s ( 8.12x)
qtoml: 7.760 s (11.17x)
tomlkit: 32.708 s (47.09x)
\eout
Install it using `pip`:

View File

@ -316,11 +316,6 @@ TOML_NAMESPACE_START
using reference = node&;
using const_reference = const node&;
/// \brief A RandomAccessIterator for iterating over elements in a toml::array.
using iterator = array_iterator;
/// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
using const_iterator = const_array_iterator;
#if TOML_LIFETIME_HOOKS
TOML_NODISCARD_CTOR
@ -794,6 +789,12 @@ TOML_NAMESPACE_START
/// \name Iterators
/// @{
/// \brief A RandomAccessIterator for iterating over elements in a toml::array.
using iterator = array_iterator;
/// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
using const_iterator = const_array_iterator;
/// \brief Returns an iterator to the first element.
TOML_NODISCARD
iterator begin() noexcept

View File

@ -330,8 +330,7 @@ TOML_NAMESPACE_START // abi namespace
/// \brief Combination mask of all indentation-enabling flags.
indentation = indent_sub_tables | indent_array_elements,
/// \brief Emit floating-point values with relaxed precision.
///
/// \brief Emit floating-point values with relaxed (human-friendly) precision.
/// \warning Setting this flag may cause serialized documents to no longer round-trip correctly
/// since floats might have a less precise value upon being written out than they did when being
/// read in. Use this flag at your own risk.

View File

@ -82,12 +82,6 @@ TOML_NAMESPACE_START
}
public:
/// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped toml::table.
using iterator = table_iterator;
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a wrapped toml::table.
using const_iterator = const_table_iterator;
/// \brief Default constructs an 'error' result.
TOML_NODISCARD_CTOR
parse_result() noexcept //
@ -278,8 +272,14 @@ TOML_NAMESPACE_START
/// \name Iterators
/// @{
/// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped toml::table.
using iterator = table_iterator;
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a wrapped toml::table.
using const_iterator = const_table_iterator;
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
/// \remarks Always returns the same value as #end() if parsing failed.
TOML_NODISCARD
table_iterator begin() noexcept
{
@ -287,7 +287,7 @@ TOML_NAMESPACE_START
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
/// \remarks Always returns the same value as #end() if parsing failed.
TOML_NODISCARD
const_table_iterator begin() const noexcept
{
@ -295,7 +295,7 @@ TOML_NAMESPACE_START
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
/// \remarks Always returns the same value as #cend() if parsing failed.
TOML_NODISCARD
const_table_iterator cbegin() const noexcept
{
@ -303,7 +303,6 @@ TOML_NAMESPACE_START
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
TOML_NODISCARD
table_iterator end() noexcept
{
@ -311,7 +310,6 @@ TOML_NAMESPACE_START
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
TOML_NODISCARD
const_table_iterator end() const noexcept
{
@ -319,7 +317,6 @@ TOML_NAMESPACE_START
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
TOML_NODISCARD
const_table_iterator cend() const noexcept
{

View File

@ -711,26 +711,24 @@ TOML_ANON_NAMESPACE_START
template <typename T>
TOML_ATTR(nonnull)
TOML_INTERNAL_LINKAGE
TOML_NEVER_INLINE
void concatenate(char*& write_pos, char* const buf_end, const T& arg) noexcept
{
static_assert(
impl::is_one_of<impl::remove_cvref<T>, std::string_view, int64_t, uint64_t, double, escaped_codepoint>,
"concatenate inputs are limited to [std::string_view, int64_t, uint64_t, double, escaped_codepoint] to "
"keep instantiations at a minimum as an anti-bloat measure (hint: to_sv will probably help)");
if (write_pos >= buf_end)
if TOML_UNLIKELY(write_pos >= buf_end)
return;
using arg_t = impl::remove_cvref<T>;
if constexpr (std::is_same_v<arg_t, std::string_view>)
using arg_type = impl::remove_cvref<T>;
// string views
if constexpr (std::is_same_v<arg_type, std::string_view>)
{
const auto max_chars = static_cast<size_t>(buf_end - write_pos);
const auto len = max_chars < arg.length() ? max_chars : arg.length();
std::memcpy(write_pos, arg.data(), len);
write_pos += len;
}
else if constexpr (std::is_same_v<arg_t, double>)
// doubles
else if constexpr (std::is_same_v<arg_type, double>)
{
#if TOML_FLOAT_CHARCONV
const auto result = std::to_chars(write_pos, buf_end, arg);
@ -738,12 +736,14 @@ TOML_ANON_NAMESPACE_START
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss.precision(std::numeric_limits<arg_t>::max_digits10);
ss.precision(std::numeric_limits<arg_type>::max_digits10);
ss << arg;
concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
}
else if constexpr (impl::is_one_of<arg_t, int64_t, uint64_t>)
// 64-bit integers
else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>)
{
#if TOML_INT_CHARCONV
const auto result = std::to_chars(write_pos, buf_end, arg);
@ -751,12 +751,14 @@ TOML_ANON_NAMESPACE_START
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
using cast_type = std::conditional_t<std::is_signed_v<arg_t>, int64_t, uint64_t>;
using cast_type = std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
ss << static_cast<cast_type>(arg);
concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
}
else if constexpr (std::is_same_v<arg_t, escaped_codepoint>)
// escaped_codepoint
else if constexpr (std::is_same_v<arg_type, escaped_codepoint>)
{
if (arg.cp.value <= U'\x7F')
concatenate(write_pos, buf_end, to_sv(arg.cp));
@ -775,8 +777,24 @@ TOML_ANON_NAMESPACE_START
concatenate(write_pos, buf_end, std::string_view{ buf, digits + 2u });
}
}
// all other floats (fallback - coerce to double)
else if constexpr (std::is_floating_point_v<arg_type>)
concatenate(write_pos, buf_end, static_cast<double>(arg));
// all other integers (fallback - coerce to (u)int64_t)
else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>)
{
using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
}
else
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
{
static_assert(
impl::dependent_false<T>,
"concatenate() inputs are limited to std::string_views, integers, floats, and escaped_codepoint");
}
}
struct error_builder
@ -1805,7 +1823,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("underscores must be followed by digits"sv);
else if TOML_UNLIKELY(length == sizeof(chars))
set_error_and_return_default("exceeds length limit of "sv,
static_cast<uint64_t>(sizeof(chars)),
sizeof(chars),
" digits"sv,
(seen_exponent ? ""sv : " (consider using exponent notation)"sv));
else if (*cp == U'.')
@ -2028,7 +2046,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
else if (current_fragment->length == sizeof(fragment::chars))
set_error_and_return_default("fragment exceeeds maximum length of "sv,
static_cast<uint64_t>(sizeof(fragment::chars)),
sizeof(fragment::chars),
" characters"sv);
else
current_fragment->chars[current_fragment->length++] = static_cast<char>(cp->bytes[0]);
@ -2162,9 +2180,7 @@ TOML_IMPL_NAMESPACE_START
else if TOML_UNLIKELY(!traits::is_digit(*cp))
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
else if TOML_UNLIKELY(length == sizeof(digits))
set_error_and_return_default("exceeds length limit of "sv,
static_cast<uint64_t>(sizeof(digits)),
" digits"sv);
set_error_and_return_default("exceeds length limit of "sv, sizeof(digits), " digits"sv);
else
digits[length++] = static_cast<char>(cp->bytes[0]);
@ -2277,8 +2293,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
const auto month = digits[1] + digits[0] * 10u;
if (month == 0u || month > 12u)
set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv,
static_cast<uint64_t>(month));
set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv, month);
const auto max_days_in_month = month == 2u
? (is_leap_year ? 29u : 28u)
: (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u);
@ -2295,9 +2310,9 @@ TOML_IMPL_NAMESPACE_START
const auto day = digits[1] + digits[0] * 10u;
if (day == 0u || day > max_days_in_month)
set_error_and_return_default("expected day between 1 and "sv,
static_cast<uint64_t>(max_days_in_month),
max_days_in_month,
" (inclusive), saw "sv,
static_cast<uint64_t>(day));
day);
if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
@ -2323,8 +2338,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
const auto hour = digits[1] + digits[0] * 10u;
if (hour > 23u)
set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv,
static_cast<uint64_t>(hour));
set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv, hour);
set_error_and_return_if_eof({});
// ':'
@ -2337,8 +2351,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
const auto minute = digits[1] + digits[0] * 10u;
if (minute > 59u)
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv,
static_cast<uint64_t>(minute));
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
auto time = toml::time{ hour, minute };
// ':'
@ -2358,8 +2371,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
const auto second = digits[1] + digits[0] * 10u;
if (second > 59u)
set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv,
static_cast<uint64_t>(second));
set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv, second);
time.second = static_cast<decltype(time.second)>(second);
// '.' (early-exiting is allowed; fractional is optional)
@ -2379,8 +2391,7 @@ TOML_IMPL_NAMESPACE_START
else if (!is_eof())
{
if (digit_count == max_digits && is_decimal_digit(*cp))
set_error_and_return_default("fractional component exceeds maximum precision of "sv,
static_cast<uint64_t>(max_digits));
set_error_and_return_default("fractional component exceeds maximum precision of "sv, max_digits);
else if (!part_of_datetime && !is_value_terminator(*cp))
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
}
@ -2443,8 +2454,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
const auto hour = digits[1] + digits[0] * 10;
if (hour > 23)
set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv,
static_cast<int64_t>(hour));
set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv, hour);
set_error_and_return_if_eof({});
// ':'
@ -2457,8 +2467,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
const auto minute = digits[1] + digits[0] * 10;
if (minute > 59)
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv,
static_cast<int64_t>(minute));
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
offset.minutes = static_cast<decltype(offset.minutes)>((hour * 60 + minute) * sign);
}
@ -2527,7 +2536,7 @@ TOML_IMPL_NAMESPACE_START
const depth_counter_scope depth_counter{ nested_values };
if TOML_UNLIKELY(nested_values > max_nested_values)
set_error_and_return_default("exceeded maximum nested value depth of "sv,
static_cast<uint64_t>(max_nested_values),
max_nested_values,
" (TOML_MAX_NESTED_VALUES)"sv);
// check if it begins with some control character
@ -2837,7 +2846,7 @@ TOML_IMPL_NAMESPACE_START
utf8_buffered_reader::max_history_length - 2u;
if TOML_UNLIKELY(!eof_while_scanning && advance_count > max_numeric_value_length)
set_error_and_return_default("numeric value too long to identify type - cannot exceed "sv,
static_cast<uint64_t>(max_numeric_value_length),
max_numeric_value_length,
" characters"sv);
val.reset(new value{ parse_integer<10>() });

View File

@ -186,9 +186,35 @@ TOML_NAMESPACE_START
/// \brief A TOML table.
///
/// \remarks The interface of this type is modeled after std::map, with some
/// \detail The interface of this type is modeled after std::map, with some
/// additional considerations made for the heterogeneous nature of a
/// TOML table.
///
/// \cpp
/// toml::table tbl = toml::parse(R"(
///
/// [animals]
/// cats = [ "tiger", "lion", "puma" ]
/// birds = [ "macaw", "pigeon", "canary" ]
/// fish = [ "salmon", "trout", "carp" ]
///
/// )"sv);
///
/// // operator[] retrieves node-views
/// std::cout << "cats: " << tbl["animals"]["cats"] << "\n";
/// std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n";
///
/// // at_path() does fully-qualified "toml path" lookups
/// std::cout << "cats: " << tbl.at_path("animals.cats") << "\n";
/// std::cout << "fish[1]: " << tbl.at_path("animals.fish[1]") << "\n";
/// \ecpp
///
/// \out
/// cats: ['tiger', 'lion', 'puma']
/// fish[1] : 'trout'
/// cats : ['tiger', 'lion', 'puma']
/// fish[1] : 'trout'
/// \eout
class table : public node
{
private:
@ -208,12 +234,6 @@ TOML_NAMESPACE_START
/// \endcond
public:
/// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table.
using iterator = toml::table_iterator;
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table.
using const_iterator = toml::const_table_iterator;
#if TOML_LIFETIME_HOOKS
TOML_NODISCARD_CTOR
@ -779,6 +799,12 @@ TOML_NAMESPACE_START
/// \name Iterators
/// @{
/// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table.
using iterator = toml::table_iterator;
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table.
using const_iterator = toml::const_table_iterator;
/// \brief Returns an iterator to the first key-value pair.
TOML_PURE_INLINE_GETTER
iterator begin() noexcept

110
toml.hpp
View File

@ -5288,10 +5288,6 @@ TOML_NAMESPACE_START
using reference = node&;
using const_reference = const node&;
using iterator = array_iterator;
using const_iterator = const_array_iterator;
#if TOML_LIFETIME_HOOKS
TOML_NODISCARD_CTOR
@ -5620,6 +5616,10 @@ TOML_NAMESPACE_START
return *elems_.back();
}
using iterator = array_iterator;
using const_iterator = const_array_iterator;
TOML_NODISCARD
iterator begin() noexcept
{
@ -6416,11 +6416,6 @@ TOML_NAMESPACE_START
table(const impl::table_init_pair*, const impl::table_init_pair*);
public:
using iterator = toml::table_iterator;
using const_iterator = toml::const_table_iterator;
#if TOML_LIFETIME_HOOKS
TOML_NODISCARD_CTOR
@ -6774,6 +6769,10 @@ TOML_NAMESPACE_START
#endif // TOML_ENABLE_WINDOWS_COMPAT
using iterator = toml::table_iterator;
using const_iterator = toml::const_table_iterator;
TOML_PURE_INLINE_GETTER
iterator begin() noexcept
{
@ -8390,10 +8389,6 @@ TOML_NAMESPACE_START
public:
using iterator = table_iterator;
using const_iterator = const_table_iterator;
TOML_NODISCARD_CTOR
parse_result() noexcept //
: err_{ true }
@ -8547,6 +8542,10 @@ TOML_NAMESPACE_START
return error();
}
using iterator = table_iterator;
using const_iterator = const_table_iterator;
TOML_NODISCARD
table_iterator begin() noexcept
{
@ -11730,26 +11729,24 @@ TOML_ANON_NAMESPACE_START
template <typename T>
TOML_ATTR(nonnull)
TOML_INTERNAL_LINKAGE
TOML_NEVER_INLINE
void concatenate(char*& write_pos, char* const buf_end, const T& arg) noexcept
{
static_assert(
impl::is_one_of<impl::remove_cvref<T>, std::string_view, int64_t, uint64_t, double, escaped_codepoint>,
"concatenate inputs are limited to [std::string_view, int64_t, uint64_t, double, escaped_codepoint] to "
"keep instantiations at a minimum as an anti-bloat measure (hint: to_sv will probably help)");
if (write_pos >= buf_end)
if TOML_UNLIKELY(write_pos >= buf_end)
return;
using arg_t = impl::remove_cvref<T>;
if constexpr (std::is_same_v<arg_t, std::string_view>)
using arg_type = impl::remove_cvref<T>;
// string views
if constexpr (std::is_same_v<arg_type, std::string_view>)
{
const auto max_chars = static_cast<size_t>(buf_end - write_pos);
const auto len = max_chars < arg.length() ? max_chars : arg.length();
std::memcpy(write_pos, arg.data(), len);
write_pos += len;
}
else if constexpr (std::is_same_v<arg_t, double>)
// doubles
else if constexpr (std::is_same_v<arg_type, double>)
{
#if TOML_FLOAT_CHARCONV
const auto result = std::to_chars(write_pos, buf_end, arg);
@ -11757,12 +11754,14 @@ TOML_ANON_NAMESPACE_START
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss.precision(std::numeric_limits<arg_t>::max_digits10);
ss.precision(std::numeric_limits<arg_type>::max_digits10);
ss << arg;
concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
}
else if constexpr (impl::is_one_of<arg_t, int64_t, uint64_t>)
// 64-bit integers
else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>)
{
#if TOML_INT_CHARCONV
const auto result = std::to_chars(write_pos, buf_end, arg);
@ -11770,12 +11769,14 @@ TOML_ANON_NAMESPACE_START
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
using cast_type = std::conditional_t<std::is_signed_v<arg_t>, int64_t, uint64_t>;
using cast_type = std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
ss << static_cast<cast_type>(arg);
concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
}
else if constexpr (std::is_same_v<arg_t, escaped_codepoint>)
// escaped_codepoint
else if constexpr (std::is_same_v<arg_type, escaped_codepoint>)
{
if (arg.cp.value <= U'\x7F')
concatenate(write_pos, buf_end, to_sv(arg.cp));
@ -11794,8 +11795,24 @@ TOML_ANON_NAMESPACE_START
concatenate(write_pos, buf_end, std::string_view{ buf, digits + 2u });
}
}
// all other floats (fallback - coerce to double)
else if constexpr (std::is_floating_point_v<arg_type>)
concatenate(write_pos, buf_end, static_cast<double>(arg));
// all other integers (fallback - coerce to (u)int64_t)
else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>)
{
using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
}
else
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
{
static_assert(
impl::dependent_false<T>,
"concatenate() inputs are limited to std::string_views, integers, floats, and escaped_codepoint");
}
}
struct error_builder
@ -12824,7 +12841,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("underscores must be followed by digits"sv);
else if TOML_UNLIKELY(length == sizeof(chars))
set_error_and_return_default("exceeds length limit of "sv,
static_cast<uint64_t>(sizeof(chars)),
sizeof(chars),
" digits"sv,
(seen_exponent ? ""sv : " (consider using exponent notation)"sv));
else if (*cp == U'.')
@ -13047,7 +13064,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
else if (current_fragment->length == sizeof(fragment::chars))
set_error_and_return_default("fragment exceeeds maximum length of "sv,
static_cast<uint64_t>(sizeof(fragment::chars)),
sizeof(fragment::chars),
" characters"sv);
else
current_fragment->chars[current_fragment->length++] = static_cast<char>(cp->bytes[0]);
@ -13181,9 +13198,7 @@ TOML_IMPL_NAMESPACE_START
else if TOML_UNLIKELY(!traits::is_digit(*cp))
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
else if TOML_UNLIKELY(length == sizeof(digits))
set_error_and_return_default("exceeds length limit of "sv,
static_cast<uint64_t>(sizeof(digits)),
" digits"sv);
set_error_and_return_default("exceeds length limit of "sv, sizeof(digits), " digits"sv);
else
digits[length++] = static_cast<char>(cp->bytes[0]);
@ -13296,8 +13311,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
const auto month = digits[1] + digits[0] * 10u;
if (month == 0u || month > 12u)
set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv,
static_cast<uint64_t>(month));
set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv, month);
const auto max_days_in_month = month == 2u
? (is_leap_year ? 29u : 28u)
: (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u);
@ -13314,9 +13328,9 @@ TOML_IMPL_NAMESPACE_START
const auto day = digits[1] + digits[0] * 10u;
if (day == 0u || day > max_days_in_month)
set_error_and_return_default("expected day between 1 and "sv,
static_cast<uint64_t>(max_days_in_month),
max_days_in_month,
" (inclusive), saw "sv,
static_cast<uint64_t>(day));
day);
if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
@ -13342,8 +13356,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
const auto hour = digits[1] + digits[0] * 10u;
if (hour > 23u)
set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv,
static_cast<uint64_t>(hour));
set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv, hour);
set_error_and_return_if_eof({});
// ':'
@ -13356,8 +13369,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
const auto minute = digits[1] + digits[0] * 10u;
if (minute > 59u)
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv,
static_cast<uint64_t>(minute));
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
auto time = toml::time{ hour, minute };
// ':'
@ -13377,8 +13389,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
const auto second = digits[1] + digits[0] * 10u;
if (second > 59u)
set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv,
static_cast<uint64_t>(second));
set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv, second);
time.second = static_cast<decltype(time.second)>(second);
// '.' (early-exiting is allowed; fractional is optional)
@ -13398,8 +13409,7 @@ TOML_IMPL_NAMESPACE_START
else if (!is_eof())
{
if (digit_count == max_digits && is_decimal_digit(*cp))
set_error_and_return_default("fractional component exceeds maximum precision of "sv,
static_cast<uint64_t>(max_digits));
set_error_and_return_default("fractional component exceeds maximum precision of "sv, max_digits);
else if (!part_of_datetime && !is_value_terminator(*cp))
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
}
@ -13462,8 +13472,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
const auto hour = digits[1] + digits[0] * 10;
if (hour > 23)
set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv,
static_cast<int64_t>(hour));
set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv, hour);
set_error_and_return_if_eof({});
// ':'
@ -13476,8 +13485,7 @@ TOML_IMPL_NAMESPACE_START
set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
const auto minute = digits[1] + digits[0] * 10;
if (minute > 59)
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv,
static_cast<int64_t>(minute));
set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
offset.minutes = static_cast<decltype(offset.minutes)>((hour * 60 + minute) * sign);
}
@ -13546,7 +13554,7 @@ TOML_IMPL_NAMESPACE_START
const depth_counter_scope depth_counter{ nested_values };
if TOML_UNLIKELY(nested_values > max_nested_values)
set_error_and_return_default("exceeded maximum nested value depth of "sv,
static_cast<uint64_t>(max_nested_values),
max_nested_values,
" (TOML_MAX_NESTED_VALUES)"sv);
// check if it begins with some control character
@ -13855,7 +13863,7 @@ TOML_IMPL_NAMESPACE_START
utf8_buffered_reader::max_history_length - 2u;
if TOML_UNLIKELY(!eof_while_scanning && advance_count > max_numeric_value_length)
set_error_and_return_default("numeric value too long to identify type - cannot exceed "sv,
static_cast<uint64_t>(max_numeric_value_length),
max_numeric_value_length,
" characters"sv);
val.reset(new value{ parse_integer<10>() });