mirror of
https://github.com/marzer/tomlplusplus.git
synced 2024-10-02 21:12:24 +00:00
added toml::key
(closes #82)
also: - added `table::lower_bound()` - added `table::emplace_hint()` - changed `table` key type to `toml::key` - clarified value initializer static assert messages - lots of misc refactoring
This commit is contained in:
parent
6808825d3f
commit
209e9b6faa
45
CHANGELOG.md
45
CHANGELOG.md
@ -22,8 +22,8 @@ code changes at callsites or in build systems are indicated with ⚠️.
|
||||
|
||||
#### Fixes:
|
||||
- ⚠️ fixed incorrect `noexcept` specifications on many functions
|
||||
- fixed `json_formatter` not formatting inf and nan incorrectly
|
||||
- fixed `table` init-list constructor requiring double-brackets
|
||||
- fixed `toml::json_formatter` not formatting inf and nan incorrectly
|
||||
- fixed `toml::table` init-list constructor requiring double-brackets
|
||||
- fixed `TOML_API` + extern templates causing linker errors in some circumstances
|
||||
- fixed an illegal table redefinition edge case (#112) (@python36)
|
||||
- fixed documentation issues
|
||||
@ -34,32 +34,37 @@ code changes at callsites or in build systems are indicated with ⚠️.
|
||||
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
|
||||
|
||||
#### Additions:
|
||||
- added `array::at()` and `table::at()`
|
||||
- added `array::replace()` (#109) (@LebJe)
|
||||
- added `array::resize()` param `default_init_flags`
|
||||
- added `format_flags::allow_binary_integers`
|
||||
- added `format_flags::allow_hexadecimal_integers`
|
||||
- added `format_flags::allow_octal_integers`
|
||||
- added `format_flags::allow_real_tabs_in_strings`
|
||||
- added `format_flags::indent_array_elements`
|
||||
- added `format_flags::indent_sub_tables`
|
||||
- added `format_flags::quote_infinities_and_nans`
|
||||
- added `operator->` to `value` for class types
|
||||
- added `operator->` to `toml::value` for class types
|
||||
- added `parse_benchmark` example
|
||||
- added `toml::array::at()` (same semantics as `std::vector::at()`)
|
||||
- added `toml::array::replace()` (#109) (@LebJe)
|
||||
- added `toml::array::resize()` param `default_init_flags`
|
||||
- added `toml::format_flags::allow_binary_integers`
|
||||
- added `toml::format_flags::allow_hexadecimal_integers`
|
||||
- added `toml::format_flags::allow_octal_integers`
|
||||
- added `toml::format_flags::allow_real_tabs_in_strings`
|
||||
- added `toml::format_flags::indent_array_elements`
|
||||
- added `toml::format_flags::indent_sub_tables`
|
||||
- added `toml::format_flags::quote_infinities_and_nans`
|
||||
- added `toml::key` - provides a facility to access the source_regions of parsed keys (#82) (@vaartis)
|
||||
- added `toml::table::at()` (same semantics as `std::map::at()`)
|
||||
- added `toml::table::emplace_hint()` (same semantics as `std::map::emplace_hint()`)
|
||||
- added `toml::table::lower_bound()` (same semantics as `std::map::lower_bound()`)
|
||||
- added `toml::yaml_formatter`
|
||||
- added `TOML_ENABLE_FORMATTERS` option
|
||||
- added `yaml_formatter`
|
||||
- added clang's enum annotation attributes to all enums
|
||||
- added formatter indentation flags (#120) (@W4RH4WK)
|
||||
- added magic `value_flags` constant `preserve_source_value_flags`
|
||||
- added magic `toml::value_flags` constant `toml::preserve_source_value_flags`
|
||||
- added support for Unicode 14.0
|
||||
- added value flags to array + table insert methods (#44) (@levicki)
|
||||
|
||||
#### Changes:
|
||||
- ⚠️ `format_flags` is now backed by `uint64_t` (was previously `uint8_t`)
|
||||
- ⚠️ `source_index` is now an alias for `uint32_t` unconditionally (was previously dependent on `TOML_LARGE_FILES`)
|
||||
- ⚠️ `value_flags` is now backed by `uint16_t` (was previously `uint8_t`)
|
||||
- ⚠️ `toml::format_flags` is now backed by `uint64_t` (was previously `uint8_t`)
|
||||
- ⚠️ `toml::source_index` is now an alias for `uint32_t` unconditionally (was previously dependent on `TOML_LARGE_FILES`)
|
||||
- ⚠️ `toml::table` now uses `toml::key` as the key type (was previously `std::string`)
|
||||
- ⚠️ `toml::value_flags` is now backed by `uint16_t` (was previously `uint8_t`)
|
||||
- ⚠️ made all overloaded operators 'hidden friends' where possible
|
||||
- ⚠️ renamed `default_formatter` to `toml_formatter` (`default_formatter` is now an alias)
|
||||
- ⚠️ renamed `toml::default_formatter` to `toml::toml_formatter` (`toml::default_formatter` is now an alias)
|
||||
- ⚠️ renamed `TOML_PARSER` option to `TOML_ENABLE_PARSER` (`TOML_PARSER` will continue to work but is deprecated)
|
||||
- ⚠️ renamed `TOML_UNRELEASED_FEATURES` to `TOML_ENABLE_UNRELEASED_FEATURES` (`TOML_UNRELEASED_FEATURES` will continue to work but is deprecated)
|
||||
- ⚠️ renamed `TOML_WINDOWS_COMPAT` to `TOML_ENABLE_WINDOWS_COMPAT` (`TOML_WINDOWS_COMPAT` will continue to work but is deprecated)
|
||||
@ -71,7 +76,7 @@ code changes at callsites or in build systems are indicated with ⚠️.
|
||||
- updated conformance tests
|
||||
|
||||
#### Removals:
|
||||
- ⚠️ removed `format_flags::allow_value_format_flags`
|
||||
- ⚠️ removed `toml::format_flags::allow_value_format_flags`
|
||||
- ⚠️ removed `TOML_LARGE_FILES` (it is now default - explicitly setting `TOML_LARGE_FILES` to `0` will invoke an `#error`)
|
||||
- removed unnecessary template machinery (esp. where ostreams were involved)
|
||||
- removed unnecessary uses of `final`
|
||||
|
@ -80,17 +80,18 @@ string_literals = [ '_toml' ]
|
||||
|
||||
|
||||
[autolinks]
|
||||
'(?:toml::)?parse[_ ]results?' = 'classtoml_1_1parse__result.html'
|
||||
'(?:toml::)?parse[_ ]errors?' = 'classtoml_1_1parse__error.html'
|
||||
'(?:toml::)?node[_ ]views?' = 'classtoml_1_1node__view.html'
|
||||
'(?:toml::)?json[_ ]formatters?' = 'classtoml_1_1json__formatter.html'
|
||||
'(?:toml::)?date[_-]times?' = 'structtoml_1_1date__time.html'
|
||||
'(?:toml::)?default[_ ]formatters?' = 'classtoml_1_1default__formatter.html'
|
||||
'(?:toml::)?json[_ ]formatters?' = 'classtoml_1_1json__formatter.html'
|
||||
'(?:toml::)?node[_ ]views?' = 'classtoml_1_1node__view.html'
|
||||
'(?:toml::)?parse[_ ]errors?' = 'classtoml_1_1parse__error.html'
|
||||
'(?:toml::)?parse[_ ]results?' = 'classtoml_1_1parse__result.html'
|
||||
'(?:toml::)?source[_ ]positions?' = 'structtoml_1_1source__position.html'
|
||||
'(?:toml::)?source[_ ]regions?' = 'structtoml_1_1source__region.html'
|
||||
'toml::values?' = 'classtoml_1_1value.html'
|
||||
'toml::dates?' = 'structtoml_1_1date.html'
|
||||
'toml::times?' = 'structtoml_1_1time.html'
|
||||
'(?:toml::)?time[_ ]offsets?' = 'structtoml_1_1time__offset.html'
|
||||
'(?:toml::)?date_times?' = 'structtoml_1_1date__time.html'
|
||||
'(?:toml::)?toml_formatters?' = 'classtoml_1_1toml__formatter.html'
|
||||
'(?:toml::)?json_formatters?' = 'classtoml_1_1json__formatter.html'
|
||||
'(?:toml::)?toml[_ ]formatters?' = 'classtoml_1_1toml__formatter.html'
|
||||
'(?:toml::)?yaml[_ ]formatters?' = 'classtoml_1_1yaml__formatter.html'
|
||||
'toml::dates?' = 'structtoml_1_1date.html'
|
||||
'toml::keys?' = 'classtoml_1_1key.html'
|
||||
'toml::times?' = 'structtoml_1_1time.html'
|
||||
'toml::values?' = 'classtoml_1_1value.html'
|
||||
|
@ -22,8 +22,8 @@ TOML_IMPL_NAMESPACE_START
|
||||
friend class array_iterator;
|
||||
friend class TOML_NAMESPACE::array;
|
||||
|
||||
using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator;
|
||||
using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator;
|
||||
using raw_mutable_iterator = std::vector<node_ptr>::iterator;
|
||||
using raw_const_iterator = std::vector<node_ptr>::const_iterator;
|
||||
using raw_iterator = std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
|
||||
|
||||
mutable raw_iterator raw_;
|
||||
@ -250,7 +250,7 @@ TOML_NAMESPACE_START
|
||||
/// \cond
|
||||
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
std::vector<std::unique_ptr<node>> elems_;
|
||||
std::vector<impl::node_ptr> elems_;
|
||||
|
||||
TOML_API
|
||||
void preinsertion_resize(size_t idx, size_t count);
|
||||
@ -949,10 +949,10 @@ TOML_NAMESPACE_START
|
||||
preinsertion_resize(start_idx, count);
|
||||
size_t i = start_idx;
|
||||
for (size_t e = start_idx + count - 1u; i < e; i++)
|
||||
elems_[i].reset(impl::make_node(val, flags));
|
||||
elems_[i] = impl::make_node(val, flags);
|
||||
|
||||
//# potentially move the initial value into the last element
|
||||
elems_[i].reset(impl::make_node(static_cast<ElemType&&>(val), flags));
|
||||
elems_[i] = impl::make_node(static_cast<ElemType&&>(val), flags);
|
||||
return { elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
|
||||
}
|
||||
}
|
||||
@ -1001,9 +1001,9 @@ TOML_NAMESPACE_START
|
||||
continue;
|
||||
}
|
||||
if constexpr (std::is_rvalue_reference_v<deref_type>)
|
||||
elems_[i++].reset(impl::make_node(std::move(*it), flags));
|
||||
elems_[i++] = impl::make_node(std::move(*it), flags);
|
||||
else
|
||||
elems_[i++].reset(impl::make_node(*it, flags));
|
||||
elems_[i++] = impl::make_node(*it, flags);
|
||||
}
|
||||
return { elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
|
||||
}
|
||||
@ -1104,7 +1104,7 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
|
||||
const auto it = elems_.begin() + (pos.raw_ - elems_.cbegin());
|
||||
it->reset(impl::make_node(static_cast<ElemType&&>(val), flags));
|
||||
*it = impl::make_node(static_cast<ElemType&&>(val), flags);
|
||||
return iterator{ it };
|
||||
}
|
||||
|
||||
@ -1342,8 +1342,8 @@ TOML_NAMESPACE_START
|
||||
static bool equal_to_container(const array& lhs, const T& rhs) noexcept
|
||||
{
|
||||
using element_type = std::remove_const_t<typename T::value_type>;
|
||||
static_assert(impl::is_native<element_type> || impl::is_losslessly_convertible_to_native<element_type>,
|
||||
"Container element type must be (or be promotable to) one of the TOML value types");
|
||||
static_assert(impl::is_losslessly_convertible_to_native<element_type>,
|
||||
"Container element type must be losslessly convertible one of the native TOML value types");
|
||||
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
|
@ -234,8 +234,8 @@ TOML_NAMESPACE_START
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<node> arr_storage = std::move(elems_[i]);
|
||||
const auto leaf_count = arr->total_leaf_count();
|
||||
impl::node_ptr arr_storage = std::move(elems_[i]);
|
||||
const auto leaf_count = arr->total_leaf_count();
|
||||
if (leaf_count > 1u)
|
||||
preinsertion_resize(i + 1u, leaf_count - 1u);
|
||||
flatten_child(std::move(*arr), i); // increments i
|
||||
|
@ -36,52 +36,55 @@ TOML_NAMESPACE_START
|
||||
{}
|
||||
|
||||
/// \brief Equality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator==(const date& lhs, const date& rhs) noexcept
|
||||
{
|
||||
return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator!=(const date& lhs, const date& rhs) noexcept
|
||||
{
|
||||
return lhs.year != rhs.year || lhs.month != rhs.month || lhs.day != rhs.day;
|
||||
}
|
||||
|
||||
private:
|
||||
TOML_NODISCARD
|
||||
TOML_ALWAYS_INLINE
|
||||
/// \cond
|
||||
|
||||
TOML_PURE_GETTER
|
||||
static constexpr uint32_t pack(const date& d) noexcept
|
||||
{
|
||||
return (static_cast<uint32_t>(d.year) << 16) | (static_cast<uint32_t>(d.month) << 8)
|
||||
| static_cast<uint32_t>(d.day);
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
/// \brief Less-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<(const date& lhs, const date& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) < pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<=(const date& lhs, const date& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) <= pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>(const date& lhs, const date& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) > pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>=(const date& lhs, const date& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) >= pack(rhs);
|
||||
@ -137,7 +140,7 @@ TOML_NAMESPACE_START
|
||||
{}
|
||||
|
||||
/// \brief Equality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator==(const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second
|
||||
@ -145,45 +148,48 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator!=(const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
TOML_NODISCARD
|
||||
TOML_ALWAYS_INLINE
|
||||
/// \cond
|
||||
|
||||
TOML_PURE_GETTER
|
||||
static constexpr uint64_t pack(const time& t) noexcept
|
||||
{
|
||||
return static_cast<uint64_t>(t.hour) << 48 | static_cast<uint64_t>(t.minute) << 40
|
||||
| static_cast<uint64_t>(t.second) << 32 | static_cast<uint64_t>(t.nanosecond);
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
/// \brief Less-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<(const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) < pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<=(const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) <= pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>(const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) > pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>=(const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return pack(lhs) >= pack(rhs);
|
||||
@ -247,42 +253,42 @@ TOML_NAMESPACE_START
|
||||
{}
|
||||
|
||||
/// \brief Equality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes == rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes != rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes < rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes <= rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes > rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes >= rhs.minutes;
|
||||
@ -355,28 +361,28 @@ TOML_NAMESPACE_START
|
||||
{}
|
||||
|
||||
/// \brief Returns true if this date_time does not contain timezone offset information.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
constexpr bool is_local() const noexcept
|
||||
{
|
||||
return !offset.has_value();
|
||||
}
|
||||
|
||||
/// \brief Equality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator==(const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return lhs.date == rhs.date && lhs.time == rhs.time && lhs.offset == rhs.offset;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator!=(const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<(const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
if (lhs.date != rhs.date)
|
||||
@ -387,7 +393,7 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator<=(const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
if (lhs.date != rhs.date)
|
||||
@ -398,14 +404,14 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>(const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_GETTER
|
||||
friend constexpr bool operator>=(const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
|
@ -89,6 +89,7 @@ TOML_NAMESPACE_START
|
||||
template <typename>
|
||||
class node_view;
|
||||
|
||||
class key;
|
||||
class array;
|
||||
class table;
|
||||
template <typename>
|
||||
@ -111,6 +112,8 @@ TOML_NAMESPACE_END;
|
||||
|
||||
TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
using node_ptr = std::unique_ptr<node>;
|
||||
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
|
||||
class parser;
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
|
@ -42,7 +42,7 @@ TOML_NAMESPACE_START
|
||||
print_newline(true);
|
||||
print_indent();
|
||||
|
||||
print_string(k, false);
|
||||
print_string(k.str(), false);
|
||||
print_unformatted(" : "sv);
|
||||
|
||||
const auto type = v.type();
|
||||
|
303
include/toml++/impl/key.h
Normal file
303
include/toml++/impl/key.h
Normal file
@ -0,0 +1,303 @@
|
||||
//# 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 "source_region.h"
|
||||
#include "std_utility.h"
|
||||
#include "print_to_stream.h"
|
||||
#include "header_start.h"
|
||||
|
||||
TOML_NAMESPACE_START
|
||||
{
|
||||
/// \brief A key parsed from a TOML document.
|
||||
///
|
||||
/// \detail These are used as the internal keys for a toml::table: \cpp
|
||||
/// const toml::table tbl = R"(
|
||||
/// a = 1
|
||||
/// b = 2
|
||||
/// c = 3
|
||||
/// )"_toml;
|
||||
///
|
||||
/// for (auto&& [k, v] : tbl)
|
||||
/// std::cout << "key '"sv << k << "' defined at "sv << k.source() << "\n";
|
||||
/// \ecpp
|
||||
/// \out
|
||||
/// key 'a' defined at line 2, column 5
|
||||
/// key 'b' defined at line 3, column 7
|
||||
/// key 'c' defined at line 4, column 9
|
||||
/// \eout
|
||||
class key
|
||||
{
|
||||
private:
|
||||
std::string key_;
|
||||
source_region source_;
|
||||
|
||||
public:
|
||||
/// \brief Default constructor.
|
||||
key() noexcept = default;
|
||||
|
||||
/// \brief Constructs a key from a string view and source region.
|
||||
explicit key(std::string_view k, source_region&& src = {}) //
|
||||
: key_{ k },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
/// \brief Constructs a key from a string view and source region.
|
||||
explicit key(std::string_view k, const source_region& src) //
|
||||
: key_{ k },
|
||||
source_{ src }
|
||||
{}
|
||||
|
||||
/// \brief Constructs a key from a string and source region.
|
||||
explicit key(std::string&& k, source_region&& src = {}) noexcept //
|
||||
: key_{ std::move(k) },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
/// \brief Constructs a key from a string and source region.
|
||||
explicit key(std::string&& k, const source_region& src) noexcept //
|
||||
: key_{ std::move(k) },
|
||||
source_{ src }
|
||||
{}
|
||||
|
||||
/// \brief Constructs a key from a c-string and source region.
|
||||
explicit key(const char* k, source_region&& src = {}) //
|
||||
: key_{ k },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
/// \brief Constructs a key from a c-string view and source region.
|
||||
explicit key(const char* k, const source_region& src) //
|
||||
: key_{ k },
|
||||
source_{ src }
|
||||
{}
|
||||
|
||||
#if TOML_ENABLE_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Constructs a key from a wide string view and source region.
|
||||
///
|
||||
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
|
||||
explicit key(std::wstring_view k, source_region&& src = {}) //
|
||||
: key_{ impl::narrow(k) },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
/// \brief Constructs a key from a wide string and source region.
|
||||
///
|
||||
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
|
||||
explicit key(std::wstring_view k, const source_region& src) //
|
||||
: key_{ impl::narrow(k) },
|
||||
source_{ src }
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
/// \name String operations
|
||||
/// @{
|
||||
|
||||
/// \brief Returns a view of the key's underlying string.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
std::string_view str() const noexcept
|
||||
{
|
||||
return std::string_view{ key_ };
|
||||
}
|
||||
|
||||
/// \brief Returns a view of the key's underlying string.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
/*implicit*/ operator std::string_view() const noexcept
|
||||
{
|
||||
return str();
|
||||
}
|
||||
|
||||
/// \brief Returns true if the key's underlying string is empty.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return key_.empty();
|
||||
}
|
||||
|
||||
/// \brief Returns a pointer to the start of the key's underlying string.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
const char* data() const noexcept
|
||||
{
|
||||
return key_.data();
|
||||
}
|
||||
|
||||
/// \brief Returns the length of the key's underlying string.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
size_t length() const noexcept
|
||||
{
|
||||
return key_.length();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Metadata
|
||||
/// @{
|
||||
|
||||
/// \brief Returns the source region responsible for specifying this key during parsing.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
const source_region& source() const noexcept
|
||||
{
|
||||
return source_;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Equality and Comparison
|
||||
/// \attention These operations only compare the underlying strings; source regions are ignored for the purposes of all comparison!
|
||||
/// @{
|
||||
|
||||
/// \brief Returns true if `lhs.str() == rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator==(const key& lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs.key_ == rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() != rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator!=(const key& lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs.key_ != rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() < rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator<(const key& lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs.key_ < rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() <= rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator<=(const key& lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs.key_ <= rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() > rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator>(const key& lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs.key_ > rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() >= rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator>=(const key& lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs.key_ >= rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() == rhs`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator==(const key& lhs, std::string_view rhs) noexcept
|
||||
{
|
||||
return lhs.key_ == rhs;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() != rhs`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator!=(const key& lhs, std::string_view rhs) noexcept
|
||||
{
|
||||
return lhs.key_ != rhs;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() < rhs`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator<(const key& lhs, std::string_view rhs) noexcept
|
||||
{
|
||||
return lhs.key_ < rhs;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() <= rhs`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator<=(const key& lhs, std::string_view rhs) noexcept
|
||||
{
|
||||
return lhs.key_ <= rhs;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() > rhs`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator>(const key& lhs, std::string_view rhs) noexcept
|
||||
{
|
||||
return lhs.key_ > rhs;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs.str() >= rhs`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator>=(const key& lhs, std::string_view rhs) noexcept
|
||||
{
|
||||
return lhs.key_ >= rhs;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs == rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator==(std::string_view lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs == rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs != rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator!=(std::string_view lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs != rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs < rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator<(std::string_view lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs < rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs <= rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator<=(std::string_view lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs <= rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs > rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator>(std::string_view lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs > rhs.key_;
|
||||
}
|
||||
|
||||
/// \brief Returns true if `lhs >= rhs.str()`.
|
||||
TOML_PURE_INLINE_GETTER
|
||||
friend bool operator>=(std::string_view lhs, const key& rhs) noexcept
|
||||
{
|
||||
return lhs >= rhs.key_;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \brief Prints the key's underlying string out to the stream.
|
||||
friend std::ostream& operator<<(std::ostream& lhs, const key& rhs)
|
||||
{
|
||||
impl::print_to_stream(lhs, rhs.key_);
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
/// \cond
|
||||
TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
template <typename T>
|
||||
inline constexpr bool is_key = std::is_same_v<remove_cvref<T>, toml::key>;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_key_or_convertible = is_key<T> || std::is_constructible_v<toml::key, T>;
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
/// \endcond
|
||||
|
||||
#include "header_end.h"
|
@ -13,7 +13,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
template <typename T>
|
||||
TOML_NODISCARD
|
||||
TOML_ATTR(returns_nonnull)
|
||||
auto* make_node_specialized(T && val, [[maybe_unused]] value_flags flags)
|
||||
auto* make_node_impl_specialized(T && val, [[maybe_unused]] value_flags flags)
|
||||
{
|
||||
using unwrapped_type = unwrap_node<remove_cvref<T>>;
|
||||
static_assert(!std::is_same_v<unwrapped_type, node>);
|
||||
@ -45,8 +45,20 @@ TOML_IMPL_NAMESPACE_START
|
||||
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
|
||||
"Instantiating values from wide-character strings is only "
|
||||
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
|
||||
static_assert(is_native<unwrapped_type> || is_losslessly_convertible_to_native<unwrapped_type>,
|
||||
"Value initializers must be (or be promotable to) one of the TOML value types");
|
||||
|
||||
if constexpr (!is_losslessly_convertible_to_native<unwrapped_type>)
|
||||
{
|
||||
if constexpr (std::is_same_v<native_type, int64_t>)
|
||||
static_assert(dependent_false<T>,
|
||||
"Integral value initializers must be losslessly convertible to int64_t");
|
||||
else if constexpr (std::is_same_v<native_type, double>)
|
||||
static_assert(dependent_false<T>,
|
||||
"Floating-point value initializers must be losslessly convertible to double");
|
||||
else
|
||||
static_assert(
|
||||
dependent_false<T>,
|
||||
"Value initializers must be losslessly convertible to one of the TOML value types");
|
||||
}
|
||||
|
||||
if constexpr (is_wide_string<T>)
|
||||
{
|
||||
@ -69,12 +81,12 @@ TOML_IMPL_NAMESPACE_START
|
||||
|
||||
template <typename T>
|
||||
TOML_NODISCARD
|
||||
auto* make_node(T && val, value_flags flags = preserve_source_value_flags)
|
||||
auto* make_node_impl(T && val, value_flags flags = preserve_source_value_flags)
|
||||
{
|
||||
using type = unwrap_node<remove_cvref<T>>;
|
||||
if constexpr (std::is_same_v<type, node> || is_node_view<type>)
|
||||
using unwrapped_type = unwrap_node<remove_cvref<T>>;
|
||||
if constexpr (std::is_same_v<unwrapped_type, node> || is_node_view<unwrapped_type>)
|
||||
{
|
||||
if constexpr (is_node_view<type>)
|
||||
if constexpr (is_node_view<unwrapped_type>)
|
||||
{
|
||||
if (!val)
|
||||
return static_cast<toml::node*>(nullptr);
|
||||
@ -83,24 +95,24 @@ TOML_IMPL_NAMESPACE_START
|
||||
return static_cast<T&&>(val).visit(
|
||||
[flags](auto&& concrete) {
|
||||
return static_cast<toml::node*>(
|
||||
make_node_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
|
||||
make_node_impl_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
|
||||
});
|
||||
}
|
||||
else
|
||||
return make_node_specialized(static_cast<T&&>(val), flags);
|
||||
return make_node_impl_specialized(static_cast<T&&>(val), flags);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TOML_NODISCARD
|
||||
auto* make_node(inserter<T> && val, value_flags flags = preserve_source_value_flags)
|
||||
auto* make_node_impl(inserter<T> && val, value_flags flags = preserve_source_value_flags)
|
||||
{
|
||||
return make_node(static_cast<T&&>(val.value), flags);
|
||||
return make_node_impl(static_cast<T&&>(val.value), flags);
|
||||
}
|
||||
|
||||
template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
|
||||
struct inserted_type_of_
|
||||
{
|
||||
using type = std::remove_pointer_t<decltype(make_node(std::declval<T>()))>;
|
||||
using type = std::remove_pointer_t<decltype(make_node_impl(std::declval<T>()))>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -114,6 +126,13 @@ TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
TOML_NODISCARD
|
||||
node_ptr make_node(T && val, value_flags flags = preserve_source_value_flags)
|
||||
{
|
||||
return node_ptr{ make_node_impl(static_cast<T&&>(val), flags) };
|
||||
}
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
/// \endcond
|
||||
|
@ -614,7 +614,7 @@ TOML_NAMESPACE_START
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<T>&, template <typename T>);
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
TOML_CONSTRAINED_TEMPLATE((impl::is_native<T> || impl::is_losslessly_convertible_to_native<T>), typename T)
|
||||
TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>, typename T)
|
||||
TOML_NODISCARD
|
||||
friend bool operator==(const node_view& lhs, const T& rhs) noexcept(!impl::is_wide_string<T>)
|
||||
{
|
||||
@ -636,11 +636,10 @@ TOML_NAMESPACE_START
|
||||
return val && *val == rhs;
|
||||
}
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(
|
||||
const node_view&,
|
||||
const T&,
|
||||
TOML_CONSTRAINED_TEMPLATE((impl::is_native<T> || impl::is_losslessly_convertible_to_native<T>),
|
||||
typename T));
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&,
|
||||
const T&,
|
||||
TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>,
|
||||
typename T));
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as the RHS initializer list.
|
||||
template <typename T>
|
||||
|
@ -875,101 +875,49 @@ TOML_ANON_NAMESPACE_START
|
||||
#define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
|
||||
#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
|
||||
|
||||
// Q: "why not std::unique_ptr??
|
||||
// A: It caused a lot of bloat on some implementations so this exists an internal substitute.
|
||||
class node_ptr
|
||||
{
|
||||
private:
|
||||
node* node_ = {};
|
||||
|
||||
public:
|
||||
TOML_NODISCARD_CTOR
|
||||
node_ptr() noexcept = default;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit node_ptr(node* n) noexcept //
|
||||
: node_{ n }
|
||||
{}
|
||||
|
||||
~node_ptr() noexcept
|
||||
{
|
||||
delete node_;
|
||||
}
|
||||
|
||||
node_ptr& operator=(node* val) noexcept
|
||||
{
|
||||
if (val != node_)
|
||||
{
|
||||
delete node_;
|
||||
node_ = val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_ptr(const node_ptr&) = delete;
|
||||
node_ptr& operator=(const node_ptr&) = delete;
|
||||
node_ptr(node_ptr&&) = delete;
|
||||
node_ptr& operator=(node_ptr&&) = delete;
|
||||
|
||||
TOML_PURE_INLINE_GETTER
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return node_ != nullptr;
|
||||
}
|
||||
|
||||
TOML_PURE_INLINE_GETTER
|
||||
node* operator->() noexcept
|
||||
{
|
||||
return node_;
|
||||
}
|
||||
|
||||
TOML_NODISCARD
|
||||
node* release() noexcept
|
||||
{
|
||||
auto n = node_;
|
||||
node_ = nullptr;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
struct parsed_key_buffer
|
||||
{
|
||||
std::string buffer;
|
||||
std::vector<std::pair<size_t, size_t>> segments;
|
||||
source_region source;
|
||||
std::vector<source_position> starts;
|
||||
std::vector<source_position> ends;
|
||||
|
||||
void reset(source_position pos) noexcept
|
||||
void clear() noexcept
|
||||
{
|
||||
buffer.clear();
|
||||
segments.clear();
|
||||
source.begin = pos;
|
||||
starts.clear();
|
||||
ends.clear();
|
||||
}
|
||||
|
||||
void push_back(std::string_view segment)
|
||||
void push_back(std::string_view segment, source_position b, source_position e)
|
||||
{
|
||||
segments.push_back({ buffer.length(), segment.length() });
|
||||
buffer.append(segment);
|
||||
}
|
||||
|
||||
void finish(source_position pos) noexcept
|
||||
{
|
||||
source.end = pos;
|
||||
starts.push_back(b);
|
||||
ends.push_back(e);
|
||||
}
|
||||
|
||||
TOML_PURE_INLINE_GETTER
|
||||
std::string_view operator[](size_t i) noexcept
|
||||
std::string_view operator[](size_t i) const noexcept
|
||||
{
|
||||
return std::string_view{ buffer.c_str() + segments[i].first, segments[i].second };
|
||||
}
|
||||
|
||||
TOML_PURE_INLINE_GETTER
|
||||
std::string_view back() noexcept
|
||||
std::string_view back() const noexcept
|
||||
{
|
||||
return (*this)[segments.size() - 1u];
|
||||
}
|
||||
|
||||
TOML_PURE_INLINE_GETTER
|
||||
size_t size() noexcept
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return segments.empty();
|
||||
}
|
||||
|
||||
TOML_PURE_INLINE_GETTER
|
||||
size_t size() const noexcept
|
||||
{
|
||||
return segments.size();
|
||||
}
|
||||
@ -1755,19 +1703,18 @@ TOML_IMPL_NAMESPACE_START
|
||||
assert_not_eof();
|
||||
assert_or_assume(is_bare_key_character(*cp));
|
||||
|
||||
auto& segment = string_buffer;
|
||||
segment.clear();
|
||||
string_buffer.clear();
|
||||
|
||||
while (!is_eof())
|
||||
{
|
||||
if (!is_bare_key_character(*cp))
|
||||
break;
|
||||
|
||||
segment.append(cp->bytes, cp->count);
|
||||
string_buffer.append(cp->bytes, cp->count);
|
||||
advance_and_return_if_error({});
|
||||
}
|
||||
|
||||
return segment;
|
||||
return string_buffer;
|
||||
}
|
||||
|
||||
TOML_NODISCARD
|
||||
@ -2491,13 +2438,13 @@ TOML_IMPL_NAMESPACE_START
|
||||
}
|
||||
|
||||
TOML_NODISCARD
|
||||
array* parse_array();
|
||||
node_ptr parse_array();
|
||||
|
||||
TOML_NODISCARD
|
||||
table* parse_inline_table();
|
||||
node_ptr parse_inline_table();
|
||||
|
||||
TOML_NODISCARD
|
||||
node* parse_value_known_prefixes()
|
||||
node_ptr parse_value_known_prefixes()
|
||||
{
|
||||
return_if_error({});
|
||||
assert_not_eof();
|
||||
@ -2515,31 +2462,31 @@ TOML_IMPL_NAMESPACE_START
|
||||
|
||||
// floats beginning with '.'
|
||||
case U'.':
|
||||
return new value{ parse_float() };
|
||||
return node_ptr{ new value{ parse_float() } };
|
||||
|
||||
// strings
|
||||
case U'"': [[fallthrough]];
|
||||
case U'\'':
|
||||
return new value{ parse_string().value };
|
||||
return node_ptr{ new value{ parse_string().value } };
|
||||
|
||||
// bools
|
||||
case U't': [[fallthrough]];
|
||||
case U'f': [[fallthrough]];
|
||||
case U'T': [[fallthrough]];
|
||||
case U'F':
|
||||
return new value{ parse_boolean() };
|
||||
return node_ptr{ new value{ parse_boolean() } };
|
||||
|
||||
// inf/nan
|
||||
case U'i': [[fallthrough]];
|
||||
case U'I': [[fallthrough]];
|
||||
case U'n': [[fallthrough]];
|
||||
case U'N': return new value{ parse_inf_or_nan() };
|
||||
case U'N': return node_ptr{ new value{ parse_inf_or_nan() } };
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TOML_NODISCARD
|
||||
node* parse_value()
|
||||
node_ptr parse_value()
|
||||
{
|
||||
return_if_error({});
|
||||
assert_not_eof();
|
||||
@ -2744,7 +2691,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
if (has_any(begins_zero | begins_digit))
|
||||
{
|
||||
val = new value{ static_cast<int64_t>(chars[0] - U'0') };
|
||||
val.reset(new value{ static_cast<int64_t>(chars[0] - U'0') });
|
||||
advance(); // skip the digit
|
||||
break;
|
||||
}
|
||||
@ -2763,7 +2710,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
// typed parse functions to take over and show better diagnostics if there's an issue
|
||||
// (as opposed to the fallback "could not determine type" message)
|
||||
if (has_any(has_p))
|
||||
val = new value{ parse_hex_float() };
|
||||
val.reset(new value{ parse_hex_float() });
|
||||
else if (has_any(has_x | has_o | has_b))
|
||||
{
|
||||
int64_t i;
|
||||
@ -2785,17 +2732,17 @@ TOML_IMPL_NAMESPACE_START
|
||||
}
|
||||
return_if_error({});
|
||||
|
||||
val = new value{ i };
|
||||
val.reset(new value{ i });
|
||||
val->ref_cast<int64_t>().flags(flags);
|
||||
}
|
||||
else if (has_any(has_e) || (has_any(begins_zero | begins_digit) && chars[1] == U'.'))
|
||||
val = new value{ parse_float() };
|
||||
val.reset(new value{ parse_float() });
|
||||
else if (has_any(begins_sign))
|
||||
{
|
||||
// single-digit signed integers
|
||||
if (char_count == 2u && has_any(has_digits))
|
||||
{
|
||||
val = new value{ static_cast<int64_t>(chars[1] - U'0') * (chars[0] == U'-' ? -1LL : 1LL) };
|
||||
val.reset(new value{ static_cast<int64_t>(chars[1] - U'0') * (chars[0] == U'-' ? -1LL : 1LL) });
|
||||
advance(); // skip the sign
|
||||
advance(); // skip the digit
|
||||
break;
|
||||
@ -2803,11 +2750,11 @@ TOML_IMPL_NAMESPACE_START
|
||||
|
||||
// simple signed floats (e.g. +1.0)
|
||||
if (is_decimal_digit(chars[1]) && chars[2] == U'.')
|
||||
val = new value{ parse_float() };
|
||||
val.reset(new value{ parse_float() });
|
||||
|
||||
// signed infinity or nan
|
||||
else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
|
||||
val = new value{ parse_inf_or_nan() };
|
||||
val.reset(new value{ parse_inf_or_nan() });
|
||||
}
|
||||
|
||||
return_if_error({});
|
||||
@ -2823,14 +2770,14 @@ TOML_IMPL_NAMESPACE_START
|
||||
// binary integers
|
||||
// 0b10
|
||||
case bzero_msk | has_b:
|
||||
val = new value{ parse_integer<2>() };
|
||||
val.reset(new value{ parse_integer<2>() });
|
||||
val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
|
||||
break;
|
||||
|
||||
// octal integers
|
||||
// 0o10
|
||||
case bzero_msk | has_o:
|
||||
val = new value{ parse_integer<8>() };
|
||||
val.reset(new value{ parse_integer<8>() });
|
||||
val->ref_cast<int64_t>().flags(value_flags::format_as_octal);
|
||||
break;
|
||||
|
||||
@ -2842,12 +2789,12 @@ TOML_IMPL_NAMESPACE_START
|
||||
case bzero_msk: [[fallthrough]];
|
||||
case bdigit_msk: [[fallthrough]];
|
||||
case begins_sign | has_digits | has_minus: [[fallthrough]];
|
||||
case begins_sign | has_digits | has_plus: val = new value{ parse_integer<10>() }; break;
|
||||
case begins_sign | has_digits | has_plus: val.reset(new value{ parse_integer<10>() }); break;
|
||||
|
||||
// hexadecimal integers
|
||||
// 0x10
|
||||
case bzero_msk | has_x:
|
||||
val = new value{ parse_integer<16>() };
|
||||
val.reset(new value{ parse_integer<16>() });
|
||||
val->ref_cast<int64_t>().flags(value_flags::format_as_hexadecimal);
|
||||
break;
|
||||
|
||||
@ -2900,7 +2847,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
case begins_sign | has_digits | has_e | signs_msk: [[fallthrough]];
|
||||
case begins_sign | has_digits | has_dot | has_minus: [[fallthrough]];
|
||||
case begins_sign | has_digits | has_dot | has_e | has_minus:
|
||||
val = new value{ parse_float() };
|
||||
val.reset(new value{ parse_float() });
|
||||
break;
|
||||
|
||||
// hexadecimal floats
|
||||
@ -2934,7 +2881,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
case begins_sign | has_digits | has_x | has_dot | has_p | has_minus: [[fallthrough]];
|
||||
case begins_sign | has_digits | has_x | has_dot | has_p | has_plus: [[fallthrough]];
|
||||
case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
|
||||
val = new value{ parse_hex_float() };
|
||||
val.reset(new value{ parse_hex_float() });
|
||||
break;
|
||||
|
||||
// times
|
||||
@ -2944,12 +2891,12 @@ TOML_IMPL_NAMESPACE_START
|
||||
case bzero_msk | has_colon: [[fallthrough]];
|
||||
case bzero_msk | has_colon | has_dot: [[fallthrough]];
|
||||
case bdigit_msk | has_colon: [[fallthrough]];
|
||||
case bdigit_msk | has_colon | has_dot: val = new value{ parse_time() }; break;
|
||||
case bdigit_msk | has_colon | has_dot: val.reset(new value{ parse_time() }); break;
|
||||
|
||||
// local dates
|
||||
// YYYY-MM-DD
|
||||
case bzero_msk | has_minus: [[fallthrough]];
|
||||
case bdigit_msk | has_minus: val = new value{ parse_date() }; break;
|
||||
case bdigit_msk | has_minus: val.reset(new value{ parse_date() }); break;
|
||||
|
||||
// date-times
|
||||
// YYYY-MM-DDTHH:MM
|
||||
@ -2988,7 +2935,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t: [[fallthrough]];
|
||||
case bdigit_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
|
||||
case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
|
||||
val = new value{ parse_date_time() };
|
||||
val.reset(new value{ parse_date_time() });
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3012,7 +2959,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
#endif
|
||||
|
||||
val->source_ = { begin_pos, current_position(1), reader.source_path() };
|
||||
return val.release();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool parse_key()
|
||||
@ -3022,9 +2969,8 @@ TOML_IMPL_NAMESPACE_START
|
||||
assert_or_assume(is_bare_key_character(*cp) || is_string_delimiter(*cp));
|
||||
push_parse_scope("key"sv);
|
||||
|
||||
key_buffer.reset(current_position());
|
||||
key_buffer.clear();
|
||||
recording_whitespace = false;
|
||||
std::string_view pending_key_segment;
|
||||
|
||||
while (!is_error())
|
||||
{
|
||||
@ -3033,9 +2979,12 @@ TOML_IMPL_NAMESPACE_START
|
||||
set_error_and_return_default("bare keys may not begin with unicode combining marks"sv);
|
||||
#endif
|
||||
|
||||
std::string_view key_segment;
|
||||
const auto key_begin = current_position();
|
||||
|
||||
// bare_key_segment
|
||||
if (is_bare_key_character(*cp))
|
||||
pending_key_segment = parse_bare_key_segment();
|
||||
key_segment = parse_bare_key_segment();
|
||||
|
||||
// "quoted key segment"
|
||||
else if (is_string_delimiter(*cp))
|
||||
@ -3051,12 +3000,12 @@ TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
set_error_at(begin_pos,
|
||||
"multi-line strings are prohibited in "sv,
|
||||
key_buffer.segments.empty() ? ""sv : "dotted "sv,
|
||||
key_buffer.empty() ? ""sv : "dotted "sv,
|
||||
"keys"sv);
|
||||
return_after_error({});
|
||||
}
|
||||
else
|
||||
pending_key_segment = str.value;
|
||||
key_segment = str.value;
|
||||
}
|
||||
|
||||
// ???
|
||||
@ -3065,11 +3014,13 @@ TOML_IMPL_NAMESPACE_START
|
||||
to_sv(*cp),
|
||||
"'"sv);
|
||||
|
||||
const auto key_end = current_position();
|
||||
|
||||
// whitespace following the key segment
|
||||
consume_leading_whitespace();
|
||||
|
||||
// store segment
|
||||
key_buffer.push_back(pending_key_segment);
|
||||
key_buffer.push_back(key_segment, key_begin, key_end);
|
||||
|
||||
// eof or no more key to come
|
||||
if (is_eof() || *cp != U'.')
|
||||
@ -3082,10 +3033,20 @@ TOML_IMPL_NAMESPACE_START
|
||||
}
|
||||
return_if_error({});
|
||||
|
||||
key_buffer.finish(current_position());
|
||||
return true;
|
||||
}
|
||||
|
||||
TOML_NODISCARD
|
||||
key make_key(size_t segment_index) const
|
||||
{
|
||||
TOML_ASSERT(key_buffer.size() > segment_index);
|
||||
|
||||
return key{
|
||||
key_buffer[segment_index],
|
||||
source_region{ key_buffer.starts[segment_index], key_buffer.ends[segment_index], root.source().path }
|
||||
};
|
||||
}
|
||||
|
||||
TOML_NODISCARD
|
||||
table* parse_table_header()
|
||||
{
|
||||
@ -3154,108 +3115,90 @@ TOML_IMPL_NAMESPACE_START
|
||||
if (!is_eof() && !consume_comment() && !consume_line_break())
|
||||
set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
|
||||
}
|
||||
TOML_ASSERT(!key_buffer.segments.empty());
|
||||
TOML_ASSERT(!key_buffer.empty());
|
||||
|
||||
// check if each parent is a table/table array, or can be created implicitly as a table.
|
||||
auto parent = &root;
|
||||
table* parent = &root;
|
||||
for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++)
|
||||
{
|
||||
const auto segment = key_buffer[i];
|
||||
auto child = parent->get(segment);
|
||||
if (!child)
|
||||
const std::string_view segment = key_buffer[i];
|
||||
auto pit = parent->lower_bound(segment);
|
||||
|
||||
// parent already existed
|
||||
if (pit != parent->end() && pit->first == segment)
|
||||
{
|
||||
child = parent->map_.emplace(segment, new table{}).first->second.get();
|
||||
implicit_tables.push_back(&child->ref_cast<table>());
|
||||
child->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
parent = &child->ref_cast<table>();
|
||||
}
|
||||
else if (child->is_table())
|
||||
{
|
||||
parent = &child->ref_cast<table>();
|
||||
}
|
||||
else if (child->is_array()
|
||||
&& impl::find(table_arrays.begin(), table_arrays.end(), &child->ref_cast<array>()))
|
||||
{
|
||||
// table arrays are a special case;
|
||||
// the spec dictates we select the most recently declared element in the array.
|
||||
TOML_ASSERT(!child->ref_cast<array>().elems_.empty());
|
||||
TOML_ASSERT(child->ref_cast<array>().elems_.back()->is_table());
|
||||
parent = &child->ref_cast<array>().back().ref_cast<table>();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_arr && child->type() == node_type::table)
|
||||
set_error_and_return_default("cannot redefine existing table '"sv,
|
||||
to_sv(recording_buffer),
|
||||
"'"sv);
|
||||
node& p = pit->second;
|
||||
|
||||
if (auto tbl = p.as_table())
|
||||
parent = tbl;
|
||||
else if (auto arr = p.as_array(); arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
|
||||
{
|
||||
// table arrays are a special case;
|
||||
// the spec dictates we select the most recently declared element in the array.
|
||||
TOML_ASSERT(!arr->elems_.empty());
|
||||
TOML_ASSERT(arr->elems_.back()->is_table());
|
||||
parent = &arr->back().ref_cast<table>();
|
||||
}
|
||||
else
|
||||
set_error_and_return_default("cannot redefine existing "sv,
|
||||
to_sv(child->type()),
|
||||
" '"sv,
|
||||
to_sv(recording_buffer),
|
||||
"' as "sv,
|
||||
is_arr ? "array-of-tables"sv : "table"sv);
|
||||
}
|
||||
}
|
||||
|
||||
// check the last parent table for a node matching the last key.
|
||||
// if there was no matching node, then sweet;
|
||||
// we can freely instantiate a new table/table array.
|
||||
const auto last_segment = key_buffer.back();
|
||||
auto matching_node = parent->get(last_segment);
|
||||
if (!matching_node)
|
||||
{
|
||||
// if it's an array we need to make the array and it's first table element,
|
||||
// set the starting regions, and return the table element
|
||||
if (is_arr)
|
||||
{
|
||||
array& tbl_arr = parent->emplace<array>(last_segment).first->second.ref_cast<array>();
|
||||
table_arrays.push_back(&tbl_arr);
|
||||
tbl_arr.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
|
||||
table& tbl = tbl_arr.emplace_back<table>();
|
||||
tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
return &tbl;
|
||||
{
|
||||
if (!is_arr && p.type() == node_type::table)
|
||||
set_error_and_return_default("cannot redefine existing table '"sv,
|
||||
to_sv(recording_buffer),
|
||||
"'"sv);
|
||||
else
|
||||
set_error_and_return_default("cannot redefine existing "sv,
|
||||
to_sv(p.type()),
|
||||
" '"sv,
|
||||
to_sv(recording_buffer),
|
||||
"' as "sv,
|
||||
is_arr ? "array-of-tables"sv : "table"sv);
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise we're just making a table
|
||||
// need to create a new implicit table
|
||||
else
|
||||
{
|
||||
table& tbl = parent->emplace<table>(last_segment).first->second.ref_cast<table>();
|
||||
tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
return &tbl;
|
||||
pit = parent->emplace_hint<table>(pit, make_key(i));
|
||||
table& p = pit->second.ref_cast<table>();
|
||||
p.source_ = pit->first.source();
|
||||
|
||||
implicit_tables.push_back(&p);
|
||||
parent = &p;
|
||||
}
|
||||
}
|
||||
|
||||
const auto last_segment = key_buffer.back();
|
||||
auto it = parent->lower_bound(last_segment);
|
||||
|
||||
// if there was already a matching node some sanity checking is necessary;
|
||||
// this is ok if we're making an array and the existing element is already an array (new element)
|
||||
// or if we're making a table and the existing element is an implicitly-created table (promote it),
|
||||
// otherwise this is a redefinition error.
|
||||
else
|
||||
if (it != parent->end() && it->first == last_segment)
|
||||
{
|
||||
if (is_arr && matching_node->is_array()
|
||||
&& impl::find(table_arrays.begin(), table_arrays.end(), &matching_node->ref_cast<array>()))
|
||||
node& matching_node = it->second;
|
||||
if (auto arr = matching_node.as_array();
|
||||
is_arr && arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
|
||||
{
|
||||
table& tbl = matching_node->ref_cast<array>().emplace_back<table>();
|
||||
table& tbl = arr->emplace_back<table>();
|
||||
tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
return &tbl;
|
||||
}
|
||||
|
||||
else if (!is_arr && matching_node->is_table() && !implicit_tables.empty())
|
||||
else if (auto tbl = matching_node.as_table(); !is_arr && tbl && !implicit_tables.empty())
|
||||
{
|
||||
table& tbl = matching_node->ref_cast<table>();
|
||||
if (auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), &tbl);
|
||||
found && (tbl.empty() || tbl.is_homogeneous<table>()))
|
||||
if (auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), tbl);
|
||||
found && (tbl->empty() || tbl->is_homogeneous<table>()))
|
||||
{
|
||||
implicit_tables.erase(implicit_tables.cbegin() + (found - implicit_tables.data()));
|
||||
tbl.source_.begin = header_begin_pos;
|
||||
tbl.source_.end = header_end_pos;
|
||||
return &tbl;
|
||||
tbl->source_.begin = header_begin_pos;
|
||||
tbl->source_.end = header_end_pos;
|
||||
return tbl;
|
||||
}
|
||||
}
|
||||
|
||||
// if we get here it's a redefinition error.
|
||||
if (!is_arr && matching_node->type() == node_type::table)
|
||||
if (!is_arr && matching_node.type() == node_type::table)
|
||||
{
|
||||
set_error_at(header_begin_pos,
|
||||
"cannot redefine existing table '"sv,
|
||||
@ -3267,7 +3210,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
set_error_at(header_begin_pos,
|
||||
"cannot redefine existing "sv,
|
||||
to_sv(matching_node->type()),
|
||||
to_sv(matching_node.type()),
|
||||
" '"sv,
|
||||
to_sv(recording_buffer),
|
||||
"' as "sv,
|
||||
@ -3275,6 +3218,35 @@ TOML_IMPL_NAMESPACE_START
|
||||
return_after_error({});
|
||||
}
|
||||
}
|
||||
|
||||
// there was no matching node, sweet - we can freely instantiate a new table/table array.
|
||||
else
|
||||
{
|
||||
auto last_key = make_key(key_buffer.size() - 1u);
|
||||
|
||||
// if it's an array we need to make the array and it's first table element,
|
||||
// set the starting regions, and return the table element
|
||||
if (is_arr)
|
||||
{
|
||||
it = parent->emplace_hint<array>(it, std::move(last_key));
|
||||
array& tbl_arr = it->second.ref_cast<array>();
|
||||
table_arrays.push_back(&tbl_arr);
|
||||
tbl_arr.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
|
||||
table& tbl = tbl_arr.emplace_back<table>();
|
||||
tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
return &tbl;
|
||||
}
|
||||
|
||||
// otherwise we're just making a table
|
||||
else
|
||||
{
|
||||
it = parent->emplace_hint<table>(it, std::move(last_key));
|
||||
table& tbl = it->second.ref_cast<table>();
|
||||
tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
|
||||
return &tbl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_key_value_pair_and_insert(table* tbl)
|
||||
@ -3309,58 +3281,67 @@ TOML_IMPL_NAMESPACE_START
|
||||
if (is_value_terminator(*cp))
|
||||
set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);
|
||||
|
||||
// if it's a dotted kvp we need to spawn the sub-tables if necessary,
|
||||
// if it's a dotted kvp we need to spawn the parent sub-tables if necessary,
|
||||
// and set the target table to the second-to-last one in the chain
|
||||
if (key_buffer.size() > 1u)
|
||||
{
|
||||
for (size_t i = 0; i < key_buffer.size() - 1u; i++)
|
||||
{
|
||||
const auto segment = key_buffer[i];
|
||||
auto child = tbl->get(segment);
|
||||
if (!child)
|
||||
const std::string_view segment = key_buffer[i];
|
||||
auto pit = tbl->lower_bound(segment);
|
||||
|
||||
// parent already existed
|
||||
if (pit != tbl->end() && pit->first == segment)
|
||||
{
|
||||
child = tbl->map_.emplace(std::string{ segment }, new table{}).first->second.get();
|
||||
dotted_key_tables.push_back(&child->ref_cast<table>());
|
||||
child->source_ = key_buffer.source;
|
||||
}
|
||||
else if (!child->is_table()
|
||||
|| !(impl::find(dotted_key_tables.begin(),
|
||||
dotted_key_tables.end(),
|
||||
&child->ref_cast<table>())
|
||||
|| impl::find(implicit_tables.begin(),
|
||||
implicit_tables.end(),
|
||||
&child->ref_cast<table>())))
|
||||
{
|
||||
set_error_at(key_buffer.source.begin,
|
||||
"cannot redefine existing "sv,
|
||||
to_sv(child->type()),
|
||||
" as dotted key-value pair"sv);
|
||||
return_after_error({});
|
||||
table* p = pit->second.as_table();
|
||||
if (!p
|
||||
|| !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p)
|
||||
|| impl::find(implicit_tables.begin(), implicit_tables.end(), p)))
|
||||
{
|
||||
set_error_at(key_buffer.starts[i],
|
||||
"cannot redefine existing "sv,
|
||||
to_sv(p->type()),
|
||||
" as dotted key-value pair"sv);
|
||||
return_after_error({});
|
||||
}
|
||||
|
||||
tbl = p;
|
||||
}
|
||||
|
||||
tbl = &child->ref_cast<table>();
|
||||
// need to create a new implicit table
|
||||
else
|
||||
{
|
||||
pit = tbl->emplace_hint<table>(pit, make_key(i));
|
||||
table& p = pit->second.ref_cast<table>();
|
||||
p.source_ = pit->first.source();
|
||||
|
||||
dotted_key_tables.push_back(&p);
|
||||
tbl = &p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure this isn't a redefinition
|
||||
if (auto conflicting_node = tbl->get(key_buffer.back()))
|
||||
const std::string_view last_segment = key_buffer.back();
|
||||
auto it = tbl->lower_bound(last_segment);
|
||||
if (it != tbl->end() && it->first == last_segment)
|
||||
{
|
||||
set_error("cannot redefine existing "sv,
|
||||
to_sv(conflicting_node->type()),
|
||||
to_sv(it->second.type()),
|
||||
" '"sv,
|
||||
to_sv(recording_buffer),
|
||||
"'"sv);
|
||||
return_after_error({});
|
||||
}
|
||||
|
||||
// cache the last segment since it might get overwritten by nested tables etc.
|
||||
auto last_segment = std::string{ key_buffer.back() };
|
||||
// create the key first since the key buffer will likely get overritten during value parsing (inline tables)
|
||||
auto last_key = make_key(key_buffer.size() - 1u);
|
||||
|
||||
// now we can actually parse the value
|
||||
auto val = node_ptr{ parse_value() };
|
||||
node_ptr val = parse_value();
|
||||
return_if_error({});
|
||||
|
||||
tbl->map_.emplace(std::move(last_segment), std::unique_ptr<node>{ val.release() });
|
||||
tbl->map_.emplace_hint(it.raw_, std::move(last_key), std::move(val));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3453,8 +3434,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
parser(utf8_reader_interface&& reader_) //
|
||||
: reader{ reader_ }
|
||||
{
|
||||
root.source_ = { prev_pos, prev_pos, reader.source_path() };
|
||||
key_buffer.source.path = reader.source_path();
|
||||
root.source_ = { prev_pos, prev_pos, reader.source_path() };
|
||||
|
||||
if (!reader.peek_eof())
|
||||
{
|
||||
@ -3494,7 +3474,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
};
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array* parser::parse_array()
|
||||
node_ptr parser::parse_array()
|
||||
{
|
||||
return_if_error({});
|
||||
assert_not_eof();
|
||||
@ -3555,11 +3535,11 @@ TOML_IMPL_NAMESPACE_START
|
||||
}
|
||||
|
||||
return_if_error({});
|
||||
return reinterpret_cast<array*>(arr_ptr.release());
|
||||
return arr_ptr;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table* parser::parse_inline_table()
|
||||
node_ptr parser::parse_inline_table()
|
||||
{
|
||||
return_if_error({});
|
||||
assert_not_eof();
|
||||
@ -3640,7 +3620,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
}
|
||||
|
||||
return_if_error({});
|
||||
return reinterpret_cast<table*>(tbl_ptr.release());
|
||||
return tbl_ptr;
|
||||
}
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "array.h"
|
||||
#include "make_node.h"
|
||||
#include "node_view.h"
|
||||
#include "key.h"
|
||||
#include "header_start.h"
|
||||
|
||||
/// \cond
|
||||
@ -19,7 +20,7 @@ TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
using value_type = std::conditional_t<IsConst, const node, node>;
|
||||
|
||||
const std::string& first;
|
||||
const toml::key& first;
|
||||
value_type& second;
|
||||
};
|
||||
|
||||
@ -30,10 +31,11 @@ TOML_IMPL_NAMESPACE_START
|
||||
template <bool>
|
||||
friend class table_iterator;
|
||||
friend class TOML_NAMESPACE::table;
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
|
||||
using proxy_type = table_proxy_pair<IsConst>;
|
||||
using raw_mutable_iterator = std::map<std::string, std::unique_ptr<node>, std::less<>>::iterator;
|
||||
using raw_const_iterator = std::map<std::string, std::unique_ptr<node>, std::less<>>::const_iterator;
|
||||
using raw_mutable_iterator = std::map<toml::key, node_ptr, std::less<>>::iterator;
|
||||
using raw_const_iterator = std::map<toml::key, node_ptr, std::less<>>::const_iterator;
|
||||
using raw_iterator = std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
|
||||
|
||||
mutable raw_iterator raw_;
|
||||
@ -154,54 +156,15 @@ TOML_IMPL_NAMESPACE_START
|
||||
|
||||
struct table_init_pair
|
||||
{
|
||||
mutable std::string key;
|
||||
mutable std::unique_ptr<node> value;
|
||||
mutable toml::key key;
|
||||
mutable node_ptr value;
|
||||
|
||||
template <typename V>
|
||||
template <typename K, typename V>
|
||||
TOML_NODISCARD_CTOR
|
||||
table_init_pair(std::string&& k, V&& v, value_flags flags = preserve_source_value_flags) //
|
||||
: key{ std::move(k) },
|
||||
table_init_pair(K&& k, V&& v, value_flags flags = preserve_source_value_flags) //
|
||||
: key{ static_cast<K&&>(k) },
|
||||
value{ make_node(static_cast<V&&>(v), flags) }
|
||||
{}
|
||||
|
||||
template <typename V>
|
||||
TOML_NODISCARD_CTOR
|
||||
table_init_pair(std::string_view k, V&& v, value_flags flags = preserve_source_value_flags) //
|
||||
: key{ k },
|
||||
value{ make_node(static_cast<V&&>(v), flags) }
|
||||
{}
|
||||
|
||||
template <typename V>
|
||||
TOML_NODISCARD_CTOR
|
||||
table_init_pair(const char* k, V&& v, value_flags flags = preserve_source_value_flags) //
|
||||
: key{ k },
|
||||
value{ make_node(static_cast<V&&>(v), flags) }
|
||||
{}
|
||||
|
||||
#if TOML_ENABLE_WINDOWS_COMPAT
|
||||
|
||||
template <typename V>
|
||||
TOML_NODISCARD_CTOR
|
||||
table_init_pair(std::wstring&& k, V&& v, value_flags flags = preserve_source_value_flags) //
|
||||
: key{ narrow(k) },
|
||||
value{ make_node(static_cast<V&&>(v), flags) }
|
||||
{}
|
||||
|
||||
template <typename V>
|
||||
TOML_NODISCARD_CTOR
|
||||
table_init_pair(std::wstring_view k, V&& v, value_flags flags = preserve_source_value_flags) //
|
||||
: key{ narrow(k) },
|
||||
value{ make_node(static_cast<V&&>(v), flags) }
|
||||
{}
|
||||
|
||||
template <typename V>
|
||||
TOML_NODISCARD_CTOR
|
||||
table_init_pair(const wchar_t* k, V&& v, value_flags flags = preserve_source_value_flags) //
|
||||
: key{ narrow(std::wstring_view{ k }) },
|
||||
value{ make_node(static_cast<V&&>(v), flags) }
|
||||
{}
|
||||
|
||||
#endif
|
||||
};
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
@ -228,7 +191,7 @@ TOML_NAMESPACE_START
|
||||
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
|
||||
std::map<std::string, std::unique_ptr<node>, std::less<>> map_;
|
||||
std::map<toml::key, impl::node_ptr, std::less<>> map_;
|
||||
bool inline_ = false;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
@ -807,56 +770,56 @@ TOML_NAMESPACE_START
|
||||
/// @{
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
iterator begin() noexcept
|
||||
{
|
||||
return { map_.begin() };
|
||||
return iterator{ map_.begin() };
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
const_iterator begin() const noexcept
|
||||
{
|
||||
return { map_.cbegin() };
|
||||
return const_iterator{ map_.cbegin() };
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
const_iterator cbegin() const noexcept
|
||||
{
|
||||
return { map_.cbegin() };
|
||||
return const_iterator{ map_.cbegin() };
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
iterator end() noexcept
|
||||
{
|
||||
return { map_.end() };
|
||||
return iterator{ map_.end() };
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
const_iterator end() const noexcept
|
||||
{
|
||||
return { map_.cend() };
|
||||
return const_iterator{ map_.cend() };
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
const_iterator cend() const noexcept
|
||||
{
|
||||
return { map_.cend() };
|
||||
return const_iterator{ map_.cend() };
|
||||
}
|
||||
|
||||
/// \brief Returns true if the table is empty.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return map_.empty();
|
||||
}
|
||||
|
||||
/// \brief Returns the number of key-value pairs in the table.
|
||||
TOML_NODISCARD
|
||||
TOML_PURE_INLINE_GETTER
|
||||
size_t size() const noexcept
|
||||
{
|
||||
return map_.size();
|
||||
@ -902,7 +865,7 @@ TOML_NAMESPACE_START
|
||||
/// d = 42
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam KeyType std::string (or a type convertible to it).
|
||||
/// \tparam KeyType A toml::key or any compatible string type.
|
||||
/// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
|
||||
/// (or a type promotable to one).
|
||||
/// \param key The key at which to insert the new value.
|
||||
@ -920,7 +883,7 @@ TOML_NAMESPACE_START
|
||||
/// \attention The return value will always be `{ end(), false }` if the input value was an
|
||||
/// empty toml::node_view, because no insertion can take place. This is the only circumstance
|
||||
/// in which this can occur.
|
||||
TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v<KeyType&&, std::string_view> || impl::is_wide_string<KeyType>),
|
||||
TOML_CONSTRAINED_TEMPLATE((impl::is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
|
||||
typename KeyType,
|
||||
typename ValueType)
|
||||
std::pair<iterator, bool> insert(KeyType&& key,
|
||||
@ -947,8 +910,9 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ipos = map_.lower_bound(key);
|
||||
if (ipos == map_.end() || ipos->first != key)
|
||||
const auto key_view = std::string_view{ key };
|
||||
auto ipos = map_.lower_bound(key_view);
|
||||
if (ipos == map_.end() || ipos->first != key_view)
|
||||
{
|
||||
ipos = map_.emplace_hint(ipos,
|
||||
static_cast<KeyType&&>(key),
|
||||
@ -999,8 +963,7 @@ TOML_NAMESPACE_START
|
||||
/// \remarks This function is morally equivalent to calling `insert(key, value)` for each
|
||||
/// key-value pair covered by the iterator range, so any values with keys already found in the
|
||||
/// table will not be replaced.
|
||||
TOML_CONSTRAINED_TEMPLATE((!std::is_convertible_v<Iter, std::string_view> && !impl::is_wide_string<Iter>),
|
||||
typename Iter)
|
||||
TOML_CONSTRAINED_TEMPLATE((!impl::is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>), typename Iter)
|
||||
void insert(Iter first, Iter last, value_flags flags = preserve_source_value_flags)
|
||||
{
|
||||
if (first == last)
|
||||
@ -1049,7 +1012,7 @@ TOML_NAMESPACE_START
|
||||
/// d = 42
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam KeyType std::string (or a type convertible to it).
|
||||
/// \tparam KeyType A toml::key or any compatible string type.
|
||||
/// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
|
||||
/// (or a type promotable to one).
|
||||
/// \param key The key at which to insert or assign the value.
|
||||
@ -1067,7 +1030,9 @@ TOML_NAMESPACE_START
|
||||
/// \attention The return value will always be `{ end(), false }` if the input value was
|
||||
/// an empty toml::node_view, because no insertion or assignment can take place.
|
||||
/// This is the only circumstance in which this can occur.
|
||||
template <typename KeyType, typename ValueType>
|
||||
TOML_CONSTRAINED_TEMPLATE((impl::is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
|
||||
typename KeyType,
|
||||
typename ValueType)
|
||||
std::pair<iterator, bool> insert_or_assign(KeyType&& key,
|
||||
ValueType&& val,
|
||||
value_flags flags = preserve_source_value_flags)
|
||||
@ -1094,8 +1059,9 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ipos = map_.lower_bound(key);
|
||||
if (ipos == map_.end() || ipos->first != key)
|
||||
const auto key_view = std::string_view{ key };
|
||||
auto ipos = map_.lower_bound(key_view);
|
||||
if (ipos == map_.end() || ipos->first != key_view)
|
||||
{
|
||||
ipos = map_.emplace_hint(ipos,
|
||||
static_cast<KeyType&&>(key),
|
||||
@ -1104,12 +1070,117 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
else
|
||||
{
|
||||
(*ipos).second.reset(impl::make_node(static_cast<ValueType&&>(val), flags));
|
||||
(*ipos).second = impl::make_node(static_cast<ValueType&&>(val), flags);
|
||||
return { iterator{ ipos }, false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the given key.
|
||||
///
|
||||
/// \returns An iterator to the first matching key-value pair, or #end().
|
||||
TOML_PURE_GETTER
|
||||
TOML_API
|
||||
iterator lower_bound(std::string_view key) noexcept;
|
||||
|
||||
/// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than the given key.
|
||||
///
|
||||
/// \returns An iterator to the first matching key-value pair, or #end().
|
||||
TOML_PURE_GETTER
|
||||
TOML_API
|
||||
const_iterator lower_bound(std::string_view key) const noexcept;
|
||||
|
||||
#if TOML_ENABLE_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the given key.
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
|
||||
///
|
||||
/// \returns An iterator to the first matching key-value pair, or #end().
|
||||
TOML_NODISCARD
|
||||
iterator lower_bound(std::wstring_view key)
|
||||
{
|
||||
return lower_bound(impl::narrow(key));
|
||||
}
|
||||
|
||||
/// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than the given key.
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
|
||||
///
|
||||
/// \returns An iterator to the first matching key-value pair, or #end().
|
||||
TOML_NODISCARD
|
||||
const_iterator lower_bound(std::wstring_view key) const
|
||||
{
|
||||
return lower_bound(impl::narrow(key));
|
||||
}
|
||||
|
||||
#endif // TOML_ENABLE_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Emplaces a new value at a specific key if one did not already exist.
|
||||
///
|
||||
/// \tparam ValueType toml::table, toml::array, or any native TOML value type.
|
||||
/// \tparam KeyType A toml::key or any compatible string type.
|
||||
/// \tparam ValueArgs Value constructor argument types.
|
||||
/// \param hint Iterator to the position before which the new element will be emplaced.
|
||||
/// \param key The key at which to emplace the new value.
|
||||
/// \param args Arguments to forward to the value's constructor.
|
||||
///
|
||||
/// \returns An iterator to the emplacement position (or the position of the value that prevented emplacement)
|
||||
///
|
||||
/// \note This function has exactly the same semantics as [std::map::emplace_hint()](https://en.cppreference.com/w/cpp/container/map/emplace_hint).
|
||||
TOML_CONSTRAINED_TEMPLATE((impl::is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
|
||||
typename ValueType,
|
||||
typename KeyType,
|
||||
typename... ValueArgs)
|
||||
iterator emplace_hint(const_iterator hint, KeyType&& key, ValueArgs&&... args)
|
||||
{
|
||||
static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
|
||||
"Emplacement using wide-character keys is only supported on Windows with "
|
||||
"TOML_ENABLE_WINDOWS_COMPAT enabled.");
|
||||
|
||||
static_assert(!impl::is_cvref<ValueType>, "ValueType may not be const, volatile, or a reference.");
|
||||
|
||||
if constexpr (impl::is_wide_string<KeyType>)
|
||||
{
|
||||
#if TOML_ENABLE_WINDOWS_COMPAT
|
||||
return emplace_hint<ValueType>(hint,
|
||||
impl::narrow(static_cast<KeyType&&>(key)),
|
||||
static_cast<ValueArgs&&>(args)...);
|
||||
#else
|
||||
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
using unwrapped_type = impl::unwrap_node<ValueType>;
|
||||
static_assert((impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>),
|
||||
"ValueType argument of table::emplace_hint() must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
auto ipos = map_.emplace_hint(hint.raw_, static_cast<KeyType&&>(key), nullptr);
|
||||
|
||||
// if second is nullptr then we successully claimed the key and inserted the empty sentinel,
|
||||
// so now we have to construct the actual value
|
||||
if (!ipos->second)
|
||||
{
|
||||
#if TOML_COMPILER_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
ipos->second.reset(new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
map_.erase(ipos); // strong exception guarantee
|
||||
throw;
|
||||
}
|
||||
#else
|
||||
ipos->second.reset(new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
|
||||
#endif
|
||||
}
|
||||
return ipos;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Emplaces a new value at a specific key if one did not already exist.
|
||||
///
|
||||
/// \detail \cpp
|
||||
@ -1138,7 +1209,7 @@ TOML_NAMESPACE_START
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ValueType toml::table, toml::array, or any native TOML value type.
|
||||
/// \tparam KeyType std::string (or a type convertible to it).
|
||||
/// \tparam KeyType A toml::key or any compatible string type.
|
||||
/// \tparam ValueArgs Value constructor argument types.
|
||||
/// \param key The key at which to emplace the new value.
|
||||
/// \param args Arguments to forward to the value's constructor.
|
||||
@ -1148,13 +1219,18 @@ TOML_NAMESPACE_START
|
||||
/// - A boolean indicating if the emplacement was successful.
|
||||
///
|
||||
/// \remark There is no difference between insert() and emplace() for trivial value types (floats, ints, bools).
|
||||
template <typename ValueType, typename KeyType, typename... ValueArgs>
|
||||
TOML_CONSTRAINED_TEMPLATE((impl::is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
|
||||
typename ValueType,
|
||||
typename KeyType,
|
||||
typename... ValueArgs)
|
||||
std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args)
|
||||
{
|
||||
static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
|
||||
"Emplacement using wide-character keys is only supported on Windows with "
|
||||
"TOML_ENABLE_WINDOWS_COMPAT enabled.");
|
||||
|
||||
static_assert(!impl::is_cvref<ValueType>, "ValueType may not be const, volatile, or a reference.");
|
||||
|
||||
if constexpr (impl::is_wide_string<KeyType>)
|
||||
{
|
||||
#if TOML_ENABLE_WINDOWS_COMPAT
|
||||
@ -1165,17 +1241,18 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
else
|
||||
{
|
||||
using type = impl::unwrap_node<ValueType>;
|
||||
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
|
||||
"The emplacement type argument of table::emplace() must be one "
|
||||
using unwrapped_type = impl::unwrap_node<ValueType>;
|
||||
static_assert((impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>),
|
||||
"ValueType argument of table::emplace() must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
auto ipos = map_.lower_bound(key);
|
||||
if (ipos == map_.end() || ipos->first != key)
|
||||
const auto key_view = std::string_view{ key };
|
||||
auto ipos = map_.lower_bound(key_view);
|
||||
if (ipos == map_.end() || ipos->first != key_view)
|
||||
{
|
||||
ipos = map_.emplace_hint(ipos,
|
||||
static_cast<KeyType&&>(key),
|
||||
new impl::wrap_node<type>{ static_cast<ValueArgs&&>(args)... });
|
||||
new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
|
||||
return { iterator{ ipos }, true };
|
||||
}
|
||||
return { iterator{ ipos }, false };
|
||||
|
@ -38,8 +38,8 @@ TOML_NAMESPACE_START
|
||||
: node(other),
|
||||
inline_{ other.inline_ }
|
||||
{
|
||||
for (auto&& [k, v] : other)
|
||||
map_.emplace_hint(map_.end(), k, impl::make_node(v));
|
||||
for (auto&& [k, v] : other.map_)
|
||||
map_.emplace_hint(map_.end(), k, impl::make_node(*v));
|
||||
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
TOML_TABLE_CREATED;
|
||||
@ -64,8 +64,8 @@ TOML_NAMESPACE_START
|
||||
{
|
||||
node::operator=(rhs);
|
||||
map_.clear();
|
||||
for (auto&& [k, v] : rhs)
|
||||
map_.emplace_hint(map_.end(), k, impl::make_node(v));
|
||||
for (auto&& [k, v] : rhs.map_)
|
||||
map_.emplace_hint(map_.end(), k, impl::make_node(*v));
|
||||
inline_ = rhs.inline_;
|
||||
}
|
||||
return *this;
|
||||
@ -92,9 +92,9 @@ TOML_NAMESPACE_START
|
||||
if (ntype == node_type::none)
|
||||
ntype = map_.cbegin()->second->type();
|
||||
|
||||
for (const auto& [k, v] : map_)
|
||||
for (auto&& [k, v] : map_)
|
||||
{
|
||||
(void)k;
|
||||
static_cast<void>(k);
|
||||
if (v->type() != ntype)
|
||||
return false;
|
||||
}
|
||||
@ -114,7 +114,7 @@ TOML_NAMESPACE_START
|
||||
ntype = map_.cbegin()->second->type();
|
||||
for (const auto& [k, v] : map_)
|
||||
{
|
||||
(void)k;
|
||||
static_cast<void>(k);
|
||||
if (v->type() != ntype)
|
||||
{
|
||||
first_nonmatch = v.get();
|
||||
@ -192,6 +192,18 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::lower_bound(std::string_view key) noexcept
|
||||
{
|
||||
return iterator{ map_.lower_bound(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::const_iterator table::lower_bound(std::string_view key) const noexcept
|
||||
{
|
||||
return const_iterator{ map_.lower_bound(key) };
|
||||
}
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
|
@ -47,17 +47,14 @@ TOML_NAMESPACE_START
|
||||
/// \cond
|
||||
|
||||
using base = impl::formatter;
|
||||
std::vector<std::string_view> key_path_;
|
||||
std::vector<const key*> key_path_;
|
||||
bool pending_table_separator_ = false;
|
||||
|
||||
TOML_API
|
||||
void print_pending_table_separator();
|
||||
|
||||
TOML_API
|
||||
void print_key_segment(std::string_view);
|
||||
|
||||
TOML_API
|
||||
void print_key_path();
|
||||
void print(const key&);
|
||||
|
||||
TOML_API
|
||||
void print_inline(const toml::table&);
|
||||
|
@ -128,20 +128,9 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void toml_formatter::print_key_segment(std::string_view str)
|
||||
void toml_formatter::print(const key& k)
|
||||
{
|
||||
print_string(str, false, true);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void toml_formatter::print_key_path()
|
||||
{
|
||||
for (const auto& segment : key_path_)
|
||||
{
|
||||
if (std::addressof(segment) > key_path_.data())
|
||||
print_unformatted('.');
|
||||
print_key_segment(segment);
|
||||
}
|
||||
print_string(k.str(), false, true);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
@ -162,7 +151,7 @@ TOML_NAMESPACE_START
|
||||
print_unformatted(", "sv);
|
||||
first = true;
|
||||
|
||||
print_key_segment(k);
|
||||
print(k);
|
||||
print_unformatted(" = "sv);
|
||||
|
||||
const auto type = v.type();
|
||||
@ -262,7 +251,7 @@ TOML_NAMESPACE_START
|
||||
pending_table_separator_ = true;
|
||||
print_newline();
|
||||
print_indent();
|
||||
print_key_segment(k);
|
||||
print(k);
|
||||
print_unformatted(" = "sv);
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
@ -273,6 +262,17 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
}
|
||||
|
||||
const auto print_key_path = [&]()
|
||||
{
|
||||
size_t i{};
|
||||
for (const auto k : key_path_)
|
||||
{
|
||||
if (i++)
|
||||
print_unformatted('.');
|
||||
print(*k);
|
||||
}
|
||||
};
|
||||
|
||||
// non-inline tables
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
@ -314,7 +314,7 @@ TOML_NAMESPACE_START
|
||||
if (child_value_count == 0u && (child_table_count > 0u || child_table_array_count > 0u))
|
||||
skip_self = true;
|
||||
|
||||
key_path_.push_back(std::string_view{ k });
|
||||
key_path_.push_back(&k);
|
||||
|
||||
if (!skip_self)
|
||||
{
|
||||
@ -344,7 +344,7 @@ TOML_NAMESPACE_START
|
||||
|
||||
if (indent_sub_tables())
|
||||
increase_indent();
|
||||
key_path_.push_back(std::string_view{ k });
|
||||
key_path_.push_back(&k);
|
||||
|
||||
for (size_t i = 0; i < arr.size(); i++)
|
||||
{
|
||||
|
@ -715,7 +715,7 @@ TOML_NAMESPACE_START
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \name Equality
|
||||
/// \name Equality and Comparison
|
||||
/// @{
|
||||
|
||||
/// \brief Value equality operator.
|
||||
|
@ -82,7 +82,7 @@ TOML_NAMESPACE_START
|
||||
}
|
||||
parent_is_array = false;
|
||||
|
||||
print_string(k, false, true);
|
||||
print_string(k.str(), false, true);
|
||||
print_unformatted(": "sv);
|
||||
|
||||
const auto type = v.type();
|
||||
|
@ -551,3 +551,45 @@ fruit = []
|
||||
color = "green"
|
||||
)"sv);
|
||||
}
|
||||
|
||||
TEST_CASE("parsing - keys")
|
||||
{
|
||||
parsing_should_succeed(FILE_LINE_ARGS,
|
||||
R"(
|
||||
[a.b]
|
||||
c = "10.0.0.1"
|
||||
d = "frontend"
|
||||
e = { f.g = 79.5, h = 72.0 }
|
||||
)"sv,
|
||||
[](table&& tbl)
|
||||
{
|
||||
// ensure types are sane first
|
||||
REQUIRE(tbl["a"].is_table());
|
||||
REQUIRE(tbl["a"]["b"].is_table());
|
||||
REQUIRE(tbl["a"]["b"]["c"]);
|
||||
REQUIRE(tbl["a"]["b"]["d"]);
|
||||
REQUIRE(tbl["a"]["b"]["e"].is_table());
|
||||
REQUIRE(tbl["a"]["b"]["e"]["f"].is_table());
|
||||
REQUIRE(tbl["a"]["b"]["e"]["f"]["g"]);
|
||||
REQUIRE(tbl["a"]["b"]["e"]["h"]);
|
||||
|
||||
const auto check_key =
|
||||
[&](const auto& t, std::string_view k, source_position b, source_position e)
|
||||
{
|
||||
const toml::key& found_key = t.as_table()->find(k)->first;
|
||||
CHECK(found_key.str() == k);
|
||||
CHECK(found_key.source().begin == b);
|
||||
CHECK(found_key.source().end == e);
|
||||
CHECK(found_key.source().path == tbl.source().path);
|
||||
};
|
||||
|
||||
check_key(tbl, "a", { 2, 2 }, { 2, 3 });
|
||||
check_key(tbl["a"], "b", { 2, 4 }, { 2, 5 });
|
||||
check_key(tbl["a"]["b"], "c", { 3, 1 }, { 3, 2 });
|
||||
check_key(tbl["a"]["b"], "d", { 4, 1 }, { 4, 2 });
|
||||
check_key(tbl["a"]["b"], "e", { 5, 1 }, { 5, 2 });
|
||||
check_key(tbl["a"]["b"]["e"], "f", { 5, 7 }, { 5, 8 });
|
||||
check_key(tbl["a"]["b"]["e"]["f"], "g", { 5, 9 }, { 5, 10 });
|
||||
check_key(tbl["a"]["b"]["e"], "h", { 5, 19 }, { 5, 20 });
|
||||
});
|
||||
}
|
||||
|
@ -69,25 +69,36 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="toml::v3::value<*>" Priority="MediumLow">
|
||||
<DisplayString>{{ {val_} }}</DisplayString>
|
||||
<Type Name="toml::v3::value<std::basic_string<char,*>>" Priority="High">
|
||||
<DisplayString>{{ {val_,s8} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="val_" ExcludeView="simple">val_</Item>
|
||||
<Item Name="value" ExcludeView="simple">val_,s8</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="toml::v3::value<std::basic_string<char,*>>">
|
||||
<DisplayString>{{ {val_,s8} }}</DisplayString>
|
||||
<Type Name="toml::v3::value<*>" Priority="MediumLow">
|
||||
<DisplayString>{{ {val_} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="val_" ExcludeView="simple">val_,s8</Item>
|
||||
<Item Name="value" ExcludeView="simple">val_</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="toml::v3::source_position">
|
||||
<DisplayString>line {line}, column {column}</DisplayString>
|
||||
<DisplayString>line {line,d}, column {column,d}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="line" ExcludeView="simple">line</Item>
|
||||
<Item Name="column" ExcludeView="simple">column</Item>
|
||||
<Item Name="line" ExcludeView="simple">line,d</Item>
|
||||
<Item Name="column" ExcludeView="simple">column,d</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="toml::v3::key">
|
||||
<Intrinsic Name="source_begin_zero" Expression="!source_.begin.line && !source_.begin.column" />
|
||||
<DisplayString Condition="!source_begin_zero()">{key_,s8} ({source_.begin})</DisplayString>
|
||||
<DisplayString Condition="source_begin_zero()">{key_,s8}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[string]" ExcludeView="simple">key_,s8</Item>
|
||||
<Item Name="[begin]" ExcludeView="simple">source_.begin</Item>
|
||||
<Item Name="[end]" ExcludeView="simple">source_.end</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
<ClInclude Include="include\toml++\impl\array.h" />
|
||||
<ClInclude Include="include\toml++\impl\array.inl" />
|
||||
<ClInclude Include="include\toml++\impl\date_time.h" />
|
||||
<ClInclude Include="include\toml++\impl\key.h" />
|
||||
<ClInclude Include="include\toml++\impl\simd.h" />
|
||||
<ClInclude Include="include\toml++\impl\std_utility.h" />
|
||||
<ClInclude Include="include\toml++\impl\toml_formatter.h" />
|
||||
@ -125,4 +126,4 @@
|
||||
<Text Include="tools\requirements.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
</Project>
|
@ -133,6 +133,9 @@
|
||||
<ClInclude Include="include\toml++\impl\simd.h">
|
||||
<Filter>include\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\toml++\impl\key.h">
|
||||
<Filter>include\impl</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="toml++.props" />
|
||||
|
Loading…
Reference in New Issue
Block a user