added value flags to array + table insert methods (closes #44)

also:
- made single header generation script `#pragma once`-aware
This commit is contained in:
Mark Gillard 2021-10-29 11:12:41 +03:00
parent 467ade4efc
commit 1bf09fe500
18 changed files with 438 additions and 338 deletions

View File

@ -255,14 +255,14 @@ TOML_NAMESPACE_START
void preinsertion_resize(size_t idx, size_t count); void preinsertion_resize(size_t idx, size_t count);
template <typename T> template <typename T>
void emplace_back_if_not_empty_view(T&& val) void emplace_back_if_not_empty_view(T&& val, value_flags flags)
{ {
if constexpr (is_node_view<T>) if constexpr (is_node_view<T>)
{ {
if (!val) if (!val)
return; return;
} }
elements.emplace_back(impl::make_node(static_cast<T&&>(val))); elements.emplace_back(impl::make_node(static_cast<T&&>(val), flags));
} }
TOML_NODISCARD TOML_NODISCARD
@ -364,10 +364,10 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals) explicit array(ElemType&& val, ElemTypes&&... vals)
{ {
elements.reserve(sizeof...(ElemTypes) + 1u); elements.reserve(sizeof...(ElemTypes) + 1u);
emplace_back_if_not_empty_view(static_cast<ElemType&&>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), value_flags::none);
if constexpr (sizeof...(ElemTypes) > 0) if constexpr (sizeof...(ElemTypes) > 0)
{ {
(emplace_back_if_not_empty_view(static_cast<ElemTypes&&>(vals)), ...); (emplace_back_if_not_empty_view(static_cast<ElemTypes&&>(vals), value_flags::none), ...);
} }
#if TOML_LIFETIME_HOOKS #if TOML_LIFETIME_HOOKS
@ -586,6 +586,10 @@ TOML_NAMESPACE_START
/// (or a type promotable to one). /// (or a type promotable to one).
/// \param pos The insertion position. /// \param pos The insertion position.
/// \param val The node or value being inserted. /// \param val The node or value being inserted.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and `val` is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \returns \conditional_return{Valid input} /// \returns \conditional_return{Valid input}
/// An iterator to the newly-inserted element. /// An iterator to the newly-inserted element.
@ -595,14 +599,14 @@ TOML_NAMESPACE_START
/// \attention The return value will always be `end()` if the input value was an empty toml::node_view, /// \attention The return value will always be `end()` 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. /// because no insertion can take place. This is the only circumstance in which this can occur.
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, ElemType&& val) iterator insert(const_iterator pos, ElemType&& val, value_flags flags = value_flags::none)
{ {
if constexpr (is_node_view<ElemType>) if constexpr (is_node_view<ElemType>)
{ {
if (!val) if (!val)
return end(); return end();
} }
return { elements.emplace(pos.raw_, impl::make_node(static_cast<ElemType&&>(val))) }; return { elements.emplace(pos.raw_, impl::make_node(static_cast<ElemType&&>(val), flags)) };
} }
/// \brief Repeatedly inserts a new element starting at a specific position in the array. /// \brief Repeatedly inserts a new element starting at a specific position in the array.
@ -632,6 +636,10 @@ TOML_NAMESPACE_START
/// \param pos The insertion position. /// \param pos The insertion position.
/// \param count The number of times the node or value should be inserted. /// \param count The number of times the node or value should be inserted.
/// \param val The node or value being inserted. /// \param val The node or value being inserted.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and `val` is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \returns \conditional_return{Valid input} /// \returns \conditional_return{Valid input}
/// An iterator to the newly-inserted element. /// An iterator to the newly-inserted element.
@ -643,7 +651,7 @@ TOML_NAMESPACE_START
/// \attention The return value will always be `end()` if the input value was an empty toml::node_view, /// \attention The return value will always be `end()` 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. /// because no insertion can take place. This is the only circumstance in which this can occur.
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, size_t count, ElemType&& val) iterator insert(const_iterator pos, size_t count, ElemType&& val, value_flags flags = value_flags::none)
{ {
if constexpr (is_node_view<ElemType>) if constexpr (is_node_view<ElemType>)
{ {
@ -653,17 +661,17 @@ TOML_NAMESPACE_START
switch (count) switch (count)
{ {
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, static_cast<ElemType&&>(val)); case 1: return insert(pos, static_cast<ElemType&&>(val), flags);
default: default:
{ {
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin()); const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, count); preinsertion_resize(start_idx, count);
size_t i = start_idx; size_t i = start_idx;
for (size_t e = start_idx + count - 1u; i < e; i++) for (size_t e = start_idx + count - 1u; i < e; i++)
elements[i].reset(impl::make_node(val)); elements[i].reset(impl::make_node(val, flags));
//# potentially move the initial value into the last element //# potentially move the initial value into the last element
elements[i].reset(impl::make_node(static_cast<ElemType&&>(val))); elements[i].reset(impl::make_node(static_cast<ElemType&&>(val), flags));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
} }
@ -675,6 +683,10 @@ TOML_NAMESPACE_START
/// \param pos The insertion position. /// \param pos The insertion position.
/// \param first Iterator to the first node or value being inserted. /// \param first Iterator to the first node or value being inserted.
/// \param last Iterator to the one-past-the-last node or value being inserted. /// \param last Iterator to the one-past-the-last node or value being inserted.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and a source value is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \returns \conditional_return{Valid input} /// \returns \conditional_return{Valid input}
/// An iterator to the first newly-inserted element. /// An iterator to the first newly-inserted element.
@ -683,7 +695,7 @@ TOML_NAMESPACE_START
/// \conditional_return{All objects in the range were empty toml::node_views} /// \conditional_return{All objects in the range were empty toml::node_views}
/// A copy of pos /// A copy of pos
template <typename Iter> template <typename Iter>
iterator insert(const_iterator pos, Iter first, Iter last) iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags = value_flags::none)
{ {
const auto distance = std::distance(first, last); const auto distance = std::distance(first, last);
if (distance <= 0) if (distance <= 0)
@ -711,9 +723,9 @@ TOML_NAMESPACE_START
continue; continue;
} }
if constexpr (std::is_rvalue_reference_v<deref_type>) if constexpr (std::is_rvalue_reference_v<deref_type>)
elements[i++].reset(impl::make_node(std::move(*it))); elements[i++].reset(impl::make_node(std::move(*it), flags));
else else
elements[i++].reset(impl::make_node(*it)); elements[i++].reset(impl::make_node(*it, flags));
} }
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
@ -725,6 +737,10 @@ TOML_NAMESPACE_START
/// (or a type promotable to one). /// (or a type promotable to one).
/// \param pos The insertion position. /// \param pos The insertion position.
/// \param ilist An initializer list containing the values to be inserted. /// \param ilist An initializer list containing the values to be inserted.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and a source value is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \returns \conditional_return{Valid input} /// \returns \conditional_return{Valid input}
/// An iterator to the first newly-inserted element. /// An iterator to the first newly-inserted element.
@ -733,9 +749,11 @@ TOML_NAMESPACE_START
/// \conditional_return{All objects in the list were empty toml::node_views} /// \conditional_return{All objects in the list were empty toml::node_views}
/// A copy of pos /// A copy of pos
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) iterator insert(const_iterator pos,
std::initializer_list<ElemType> ilist,
value_flags flags = value_flags::none)
{ {
return insert(pos, ilist.begin(), ilist.end()); return insert(pos, ilist.begin(), ilist.end(), flags);
} }
/// \brief Emplaces a new element at a specific position in the array. /// \brief Emplaces a new element at a specific position in the array.
@ -908,13 +926,17 @@ TOML_NAMESPACE_START
/// ///
/// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
/// \param val The node or value being added. /// \param val The node or value being added.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and `val` is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \attention No insertion takes place if the input value is an empty toml::node_view. /// \attention No insertion takes place if the input value is an empty toml::node_view.
/// This is the only circumstance in which this can occur. /// This is the only circumstance in which this can occur.
template <typename ElemType> template <typename ElemType>
void push_back(ElemType&& val) void push_back(ElemType&& val, value_flags flags = value_flags::none)
{ {
emplace_back_if_not_empty_view(static_cast<ElemType&&>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
} }
/// \brief Emplaces a new element at the end of the array. /// \brief Emplaces a new element at the end of the array.

View File

@ -99,7 +99,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags. /// \param flags Format option flags.
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, (flags | mandatory_flags) & ~ignored_flags } : base{ source, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS) #if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
@ -128,7 +128,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags. /// \param flags Format option flags.
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit default_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept explicit default_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ result, (flags | mandatory_flags) & ~ignored_flags } : base{ result, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#endif #endif

View File

@ -73,11 +73,11 @@ TOML_NAMESPACE_START
{ {
case node_type::table: case node_type::table:
{ {
auto& n = *reinterpret_cast<const table*>(&node); auto& tbl = *reinterpret_cast<const table*>(&node);
if (n.empty()) if (tbl.empty())
return 2u; // "{}" return 2u; // "{}"
size_t weight = 3u; // "{ }" size_t weight = 3u; // "{ }"
for (auto&& [k, v] : n) for (auto&& [k, v] : tbl)
{ {
weight += k.length() + count_inline_columns(v) + 2u; // + ", " weight += k.length() + count_inline_columns(v) + 2u; // + ", "
if (weight >= line_wrap_cols) if (weight >= line_wrap_cols)
@ -88,11 +88,11 @@ TOML_NAMESPACE_START
case node_type::array: case node_type::array:
{ {
auto& n = *reinterpret_cast<const array*>(&node); auto& arr = *reinterpret_cast<const array*>(&node);
if (n.empty()) if (arr.empty())
return 2u; // "[]" return 2u; // "[]"
size_t weight = 3u; // "[ ]" size_t weight = 3u; // "[ ]"
for (auto& elem : n) for (auto& elem : arr)
{ {
weight += count_inline_columns(elem) + 2u; // + ", " weight += count_inline_columns(elem) + 2u; // + ", "
if (weight >= line_wrap_cols) if (weight >= line_wrap_cols)
@ -103,38 +103,38 @@ TOML_NAMESPACE_START
case node_type::string: case node_type::string:
{ {
auto& n = *reinterpret_cast<const value<std::string>*>(&node); // todo: proper utf8 decoding?
return n.get().length() + 2u; // + "" // todo: tab awareness?
auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
return str.length() + 2u; // + ""
} }
case node_type::integer: case node_type::integer:
{ {
auto& n = *reinterpret_cast<const value<int64_t>*>(&node); auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
auto v = n.get(); if (!val)
if (!v)
return 1u; return 1u;
size_t weight = {}; size_t weight = {};
if (v < 0) if (val < 0)
{ {
weight += 1u; weight += 1u;
v *= -1; val *= -1;
} }
return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1u; return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
} }
case node_type::floating_point: case node_type::floating_point:
{ {
auto& n = *reinterpret_cast<const value<double>*>(&node); auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
auto v = n.get(); if (val == 0.0)
if (v == 0.0)
return 3u; // "0.0" return 3u; // "0.0"
size_t weight = 2u; // ".0" size_t weight = 2u; // ".0"
if (v < 0.0) if (val < 0.0)
{ {
weight += 1u; weight += 1u;
v *= -1.0; val *= -1.0;
} }
return weight + static_cast<size_t>(log10(v)) + 1u; return weight + static_cast<size_t>(log10(val)) + 1u;
break; break;
} }
@ -252,9 +252,9 @@ TOML_NAMESPACE_START
else else
{ {
const auto original_indent = base::indent(); const auto original_indent = base::indent();
const auto multiline = const auto multiline = forces_multiline(
forces_multiline(arr, arr,
base::indent_columns * static_cast<size_t>(original_indent < 0 ? 0 : original_indent)); base::indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
impl::print_to_stream(base::stream(), "["sv); impl::print_to_stream(base::stream(), "["sv);
if (multiline) if (multiline)
{ {

View File

@ -19,14 +19,16 @@ TOML_IMPL_NAMESPACE_START
format_flags flags_; // format_flags flags_; //
int indent_; // these are set in attach() int indent_; // these are set in attach()
bool naked_newline_; // bool naked_newline_; //
std::string_view indent_string_;
size_t indent_columns_;
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
const parse_result* result_ = {}; const parse_result* result_ = {};
#endif #endif
protected: TOML_API
static constexpr size_t indent_columns = 4; void set_indent_string(std::string_view str) noexcept;
static constexpr std::string_view indent_string = " "sv;
protected:
TOML_PURE_INLINE_GETTER TOML_PURE_INLINE_GETTER
const toml::node& source() const noexcept const toml::node& source() const noexcept
{ {
@ -60,6 +62,12 @@ TOML_IMPL_NAMESPACE_START
indent_--; indent_--;
} }
TOML_PURE_INLINE_GETTER
size_t indent_columns() const noexcept
{
return indent_columns_;
}
TOML_PURE_INLINE_GETTER TOML_PURE_INLINE_GETTER
bool indent_array_elements() const noexcept bool indent_array_elements() const noexcept
{ {
@ -148,19 +156,21 @@ TOML_IMPL_NAMESPACE_START
TOML_NODISCARD TOML_NODISCARD
TOML_API TOML_API
bool dump_failed_parse_result() noexcept(!TOML_PARSER || TOML_EXCEPTIONS); bool dump_failed_parse_result();
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
formatter(const toml::node& source, format_flags flags) noexcept // formatter(const toml::node& source, format_flags flags, std::string_view indent) noexcept //
: source_{ &source }, : source_{ &source },
flags_{ flags } flags_{ flags }
{} {
set_indent_string(indent);
}
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
TOML_API TOML_API
formatter(const parse_result& result, format_flags flags) noexcept; formatter(const parse_result& result, format_flags flags, std::string_view indent) noexcept;
#endif #endif
}; };

View File

@ -25,14 +25,25 @@ TOML_IMPL_NAMESPACE_START
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
formatter::formatter(const parse_result& result, format_flags flags) noexcept // formatter::formatter(const parse_result& result, format_flags flags, std::string_view indent) noexcept //
: source_{ result ? &result.table() : nullptr }, : source_{ result ? &result.table() : nullptr },
flags_{ flags }, flags_{ flags },
result_{ &result } result_{ &result }
{} {
set_indent_string(indent);
}
#endif #endif
TOML_EXTERNAL_LINKAGE
void formatter::set_indent_string(std::string_view str) noexcept
{
indent_string_ = str.data() ? str : " "sv;
indent_columns_ = {};
for (auto c : indent_string_)
indent_columns_ += c == '\t' ? 4u : 1u;
}
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
void formatter::attach(std::ostream & stream) noexcept void formatter::attach(std::ostream & stream) noexcept
{ {
@ -62,7 +73,7 @@ TOML_IMPL_NAMESPACE_START
{ {
for (int i = 0; i < indent_; i++) for (int i = 0; i < indent_; i++)
{ {
print_to_stream(*stream_, indent_string); print_to_stream(*stream_, indent_string_);
naked_newline_ = false; naked_newline_ = false;
} }
} }
@ -216,7 +227,7 @@ TOML_IMPL_NAMESPACE_START
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
bool formatter::dump_failed_parse_result() noexcept(false) bool formatter::dump_failed_parse_result()
{ {
if (result_ && !(*result_)) if (result_ && !(*result_))
{ {
@ -230,7 +241,7 @@ TOML_IMPL_NAMESPACE_START
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
TOML_ATTR(const) TOML_ATTR(const)
bool formatter::dump_failed_parse_result() noexcept(true) bool formatter::dump_failed_parse_result()
{ {
return false; return false;
} }

View File

@ -333,10 +333,14 @@ TOML_NAMESPACE_START // abi namespace
template <typename T> template <typename T>
struct TOML_TRIVIAL_ABI inserter struct TOML_TRIVIAL_ABI inserter
{ {
T&& value; static_assert(std::is_reference_v<T>);
T value;
}; };
template <typename T> template <typename T>
inserter(T &&) -> inserter<T>; inserter(T &&) -> inserter<T&&>;
template <typename T>
inserter(T&) -> inserter<T&>;
} }
TOML_NAMESPACE_END; TOML_NAMESPACE_END;

View File

@ -72,7 +72,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags. /// \param flags Format option flags.
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, (flags | mandatory_flags) & ~ignored_flags } : base{ source, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS) #if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
@ -103,7 +103,7 @@ TOML_NAMESPACE_START
/// \param flags Format option flags. /// \param flags Format option flags.
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ result, (flags | mandatory_flags) & ~ignored_flags } : base{ result, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#endif #endif

View File

@ -13,45 +13,67 @@ TOML_IMPL_NAMESPACE_START
template <typename T> template <typename T>
TOML_NODISCARD TOML_NODISCARD
TOML_ATTR(returns_nonnull) TOML_ATTR(returns_nonnull)
auto* make_node_specialized(T && val) auto* make_node_specialized(T && val, [[maybe_unused]] value_flags flags)
{ {
using type = unwrap_node<remove_cvref<T>>; using unwrapped_type = unwrap_node<remove_cvref<T>>;
static_assert(!std::is_same_v<type, node>); static_assert(!std::is_same_v<unwrapped_type, node>);
static_assert(!is_node_view<type>); static_assert(!is_node_view<unwrapped_type>);
if constexpr (is_one_of<type, array, table>) // arrays + tables - invoke copy/move ctor
if constexpr (is_one_of<unwrapped_type, array, table>)
{ {
return new type{ static_cast<T&&>(val) }; return new unwrapped_type{ static_cast<T&&>(val) };
}
else if constexpr (is_native<type> && !std::is_same_v<remove_cvref<T>, type>)
{
return new value<type>{ static_cast<T&&>(val) };
} }
// values
else else
{ {
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT, using native_type = native_type_of<unwrapped_type>;
"Instantiating values from wide-character strings is only " using value_type = value<native_type>;
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
static_assert(is_native<type> || is_losslessly_convertible_to_native<type>,
"Value initializers must be (or be promotable to) one of the TOML value types");
using value_type = native_type_of<remove_cvref<T>>; value_type* out;
if constexpr (is_wide_string<T>)
// copy/move ctor
if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
{ {
#if TOML_WINDOWS_COMPAT out = new value_type{ static_cast<T&&>(val) };
return new value<value_type>{ narrow(static_cast<T&&>(val)) };
#else // only override the flags if the new ones are nonzero
static_assert(dependent_false<T>, "Evaluated unreachable branch!"); // (so the copy/move ctor does the right thing in the general case)
#endif if (flags != value_flags::none)
out->flags(flags);
} }
// creating from raw value
else else
return new value<value_type>{ static_cast<T&&>(val) }; {
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT,
"Instantiating values from wide-character strings is only "
"supported on Windows with TOML_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_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
out = new value_type{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
out = new value_type{ static_cast<T&&>(val) };
out->flags(flags);
}
return out;
} }
} }
template <typename T> template <typename T>
TOML_NODISCARD TOML_NODISCARD
auto* make_node(T && val) auto* make_node(T && val, value_flags flags = value_flags::none)
{ {
using type = unwrap_node<remove_cvref<T>>; using type = unwrap_node<remove_cvref<T>>;
if constexpr (std::is_same_v<type, node> || is_node_view<type>) if constexpr (std::is_same_v<type, node> || is_node_view<type>)
@ -63,19 +85,20 @@ TOML_IMPL_NAMESPACE_START
} }
return static_cast<T&&>(val).visit( return static_cast<T&&>(val).visit(
[](auto&& concrete) { [flags](auto&& concrete) {
return static_cast<toml::node*>(make_node_specialized(static_cast<decltype(concrete)&&>(concrete))); return static_cast<toml::node*>(
make_node_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
}); });
} }
else else
return make_node_specialized(static_cast<T&&>(val)); return make_node_specialized(static_cast<T&&>(val), flags);
} }
template <typename T> template <typename T>
TOML_NODISCARD TOML_NODISCARD
auto* make_node(inserter<T> && val) auto* make_node(inserter<T> && val, value_flags flags = value_flags::none)
{ {
return make_node(static_cast<T&&>(val.value)); return make_node(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>)> template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>

View File

@ -2,8 +2,8 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> //# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#pragma once #pragma once
#include "print_to_stream.h" #include "print_to_stream.h"
#include "node.h" #include "node.h"
#include "std_vector.h" #include "std_vector.h"
@ -746,7 +746,7 @@ TOML_NAMESPACE_START
TOML_NAMESPACE_END; TOML_NAMESPACE_END;
/// \cond /// \cond
#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION
#include "node_view_extern.inl" #include "node_view_extern.inl"
#endif #endif

View File

@ -14,7 +14,7 @@
#include "node_view.h" #include "node_view.h"
#include "header_start.h" #include "header_start.h"
#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION
#include "node_view_extern.inl" #include "node_view_extern.inl"
#endif // TOML_EXTERN_TEMPLATES #endif // TOML_EXTERN_TEMPLATES

View File

@ -2,7 +2,6 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> //# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#pragma once
/// \cond /// \cond
#include "node_view.h" #include "node_view.h"

View File

@ -159,46 +159,46 @@ TOML_IMPL_NAMESPACE_START
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::string&& k, V&& v) // table_init_pair(std::string&& k, V&& v, value_flags flags = value_flags::none) //
: key{ std::move(k) }, : key{ std::move(k) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::string_view k, V&& v) // table_init_pair(std::string_view k, V&& v, value_flags flags = value_flags::none) //
: key{ k }, : key{ k },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(const char* k, V&& v) // table_init_pair(const char* k, V&& v, value_flags flags = value_flags::none) //
: key{ k }, : key{ k },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::wstring&& k, V&& v) // table_init_pair(std::wstring&& k, V&& v, value_flags flags = value_flags::none) //
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::wstring_view k, V&& v) // table_init_pair(std::wstring_view k, V&& v, value_flags flags = value_flags::none) //
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(const wchar_t* k, V&& v) // table_init_pair(const wchar_t* k, V&& v, value_flags flags = value_flags::none) //
: key{ narrow(std::wstring_view{ k }) }, : key{ narrow(std::wstring_view{ k }) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
#endif #endif
@ -650,6 +650,10 @@ TOML_NAMESPACE_START
/// (or a type promotable to one). /// (or a type promotable to one).
/// \param key The key at which to insert the new value. /// \param key The key at which to insert the new value.
/// \param val The new value to insert. /// \param val The new value to insert.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and `val` is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \returns \conditional_return{Valid input} /// \returns \conditional_return{Valid input}
/// <ul> /// <ul>
@ -665,7 +669,7 @@ TOML_NAMESPACE_START
TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v<KeyType&&, std::string_view> || impl::is_wide_string<KeyType>), TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v<KeyType&&, std::string_view> || impl::is_wide_string<KeyType>),
typename KeyType, typename KeyType,
typename ValueType) typename ValueType)
std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val) std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val, value_flags flags = value_flags::none)
{ {
static_assert( static_assert(
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT, !impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
@ -680,7 +684,7 @@ TOML_NAMESPACE_START
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
return insert(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val)); return insert(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val), flags);
#else #else
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!"); static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif #endif
@ -692,7 +696,7 @@ TOML_NAMESPACE_START
{ {
ipos = map_.emplace_hint(ipos, ipos = map_.emplace_hint(ipos,
std::forward<KeyType>(key), std::forward<KeyType>(key),
impl::make_node(std::forward<ValueType>(val))); impl::make_node(std::forward<ValueType>(val), flags));
return { iterator{ ipos }, true }; return { iterator{ ipos }, true };
} }
return { iterator{ ipos }, false }; return { iterator{ ipos }, false };
@ -734,22 +738,26 @@ TOML_NAMESPACE_START
/// \tparam Iter An InputIterator to a collection of key-value pairs. /// \tparam Iter An InputIterator to a collection of key-value pairs.
/// \param first An iterator to the first value in the input collection. /// \param first An iterator to the first value in the input collection.
/// \param last An iterator to one-past-the-last value in the input collection. /// \param last An iterator to one-past-the-last value in the input collection.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and a source value is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \remarks This function is morally equivalent to calling `insert(key, value)` for each /// \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 /// key-value pair covered by the iterator range, so any values with keys already found in the
/// table will not be replaced. /// table will not be replaced.
TOML_CONSTRAINED_TEMPLATE((!std::is_convertible_v<Iter, std::string_view> && !impl::is_wide_string<Iter>), TOML_CONSTRAINED_TEMPLATE((!std::is_convertible_v<Iter, std::string_view> && !impl::is_wide_string<Iter>),
typename Iter) typename Iter)
void insert(Iter first, Iter last) void insert(Iter first, Iter last, value_flags flags = value_flags::none)
{ {
if (first == last) if (first == last)
return; return;
for (auto it = first; it != last; it++) for (auto it = first; it != last; it++)
{ {
if constexpr (std::is_rvalue_reference_v<decltype(*it)>) if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
insert(std::move((*it).first), std::move((*it).second)); insert(std::move((*it).first), std::move((*it).second), flags);
else else
insert((*it).first, (*it).second); insert((*it).first, (*it).second, flags);
} }
} }
@ -793,6 +801,10 @@ TOML_NAMESPACE_START
/// (or a type promotable to one). /// (or a type promotable to one).
/// \param key The key at which to insert or assign the value. /// \param key The key at which to insert or assign the value.
/// \param val The value to insert/assign. /// \param val The value to insert/assign.
/// \param flags Value flags to apply to new values.
///
/// \note When `flags == value_flags::none` and `val` is a value node or node_view, any existing value
/// flags will be copied, _not_ set to none.
/// ///
/// \returns \conditional_return{Valid input} /// \returns \conditional_return{Valid input}
/// <ul> /// <ul>
@ -806,7 +818,9 @@ TOML_NAMESPACE_START
/// an empty toml::node_view, because no insertion or assignment can take place. /// an empty toml::node_view, because no insertion or assignment can take place.
/// This is the only circumstance in which this can occur. /// This is the only circumstance in which this can occur.
template <typename KeyType, typename ValueType> template <typename KeyType, typename ValueType>
std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val) std::pair<iterator, bool> insert_or_assign(KeyType&& key,
ValueType&& val,
value_flags flags = value_flags::none)
{ {
static_assert( static_assert(
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT, !impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
@ -821,7 +835,7 @@ TOML_NAMESPACE_START
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
return insert_or_assign(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val)); return insert_or_assign(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val), flags);
#else #else
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!"); static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif #endif
@ -833,12 +847,12 @@ TOML_NAMESPACE_START
{ {
ipos = map_.emplace_hint(ipos, ipos = map_.emplace_hint(ipos,
std::forward<KeyType>(key), std::forward<KeyType>(key),
impl::make_node(std::forward<ValueType>(val))); impl::make_node(std::forward<ValueType>(val), flags));
return { iterator{ ipos }, true }; return { iterator{ ipos }, true };
} }
else else
{ {
(*ipos).second.reset(impl::make_node(std::forward<ValueType>(val))); (*ipos).second.reset(impl::make_node(std::forward<ValueType>(val), flags));
return { iterator{ ipos }, false }; return { iterator{ ipos }, false };
} }
} }

View File

@ -10,15 +10,13 @@
/// \cond /// \cond
TOML_IMPL_NAMESPACE_START TOML_IMPL_NAMESPACE_START
{ {
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
{ {
return codepoint == U'\t' || codepoint == U' '; return codepoint == U'\t' || codepoint == U' ';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept
{ {
// see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode // see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
@ -33,24 +31,21 @@ TOML_IMPL_NAMESPACE_START
; ;
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_whitespace(char32_t codepoint) noexcept constexpr bool is_whitespace(char32_t codepoint) noexcept
{ {
return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint); return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint);
} }
template <bool IncludeCarriageReturn = true> template <bool IncludeCarriageReturn = true>
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_ascii_line_break(char32_t codepoint) noexcept constexpr bool is_ascii_line_break(char32_t codepoint) noexcept
{ {
constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f'; constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f';
return (codepoint >= U'\n' && codepoint <= low_range_end); return (codepoint >= U'\n' && codepoint <= low_range_end);
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept
{ {
// see https://en.wikipedia.org/wiki/Whitespace_character#Unicode // see https://en.wikipedia.org/wiki/Whitespace_character#Unicode
@ -63,58 +58,50 @@ TOML_IMPL_NAMESPACE_START
} }
template <bool IncludeCarriageReturn = true> template <bool IncludeCarriageReturn = true>
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_line_break(char32_t codepoint) noexcept constexpr bool is_line_break(char32_t codepoint) noexcept
{ {
return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_non_ascii_line_break(codepoint); return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_non_ascii_line_break(codepoint);
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_string_delimiter(char32_t codepoint) noexcept constexpr bool is_string_delimiter(char32_t codepoint) noexcept
{ {
return codepoint == U'"' || codepoint == U'\''; return codepoint == U'"' || codepoint == U'\'';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_ascii_letter(char32_t codepoint) noexcept constexpr bool is_ascii_letter(char32_t codepoint) noexcept
{ {
return (codepoint >= U'a' && codepoint <= U'z') || (codepoint >= U'A' && codepoint <= U'Z'); return (codepoint >= U'a' && codepoint <= U'z') || (codepoint >= U'A' && codepoint <= U'Z');
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_binary_digit(char32_t codepoint) noexcept constexpr bool is_binary_digit(char32_t codepoint) noexcept
{ {
return codepoint == U'0' || codepoint == U'1'; return codepoint == U'0' || codepoint == U'1';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_octal_digit(char32_t codepoint) noexcept constexpr bool is_octal_digit(char32_t codepoint) noexcept
{ {
return (codepoint >= U'0' && codepoint <= U'7'); return (codepoint >= U'0' && codepoint <= U'7');
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_decimal_digit(char32_t codepoint) noexcept constexpr bool is_decimal_digit(char32_t codepoint) noexcept
{ {
return (codepoint >= U'0' && codepoint <= U'9'); return (codepoint >= U'0' && codepoint <= U'9');
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_hexadecimal_digit(char32_t c) noexcept constexpr bool is_hexadecimal_digit(char32_t c) noexcept
{ {
return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull; return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull;
} }
template <typename T> template <typename T>
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr uint_least32_t hex_to_dec(const T codepoint) noexcept constexpr uint_least32_t hex_to_dec(const T codepoint) noexcept
{ {
if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>) if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
@ -130,8 +117,7 @@ TOML_IMPL_NAMESPACE_START
//# Returns true if a codepoint belongs to any of these categories: //# Returns true if a codepoint belongs to any of these categories:
//# Ll, Lm, Lo, Lt, Lu //# Ll, Lm, Lo, Lt, Lu
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_letter(char32_t c) noexcept constexpr bool is_non_ascii_letter(char32_t c) noexcept
{ {
if (U'\xAA' > c || c > U'\U0003134A') if (U'\xAA' > c || c > U'\U0003134A')
@ -484,8 +470,7 @@ TOML_IMPL_NAMESPACE_START
//# Returns true if a codepoint belongs to any of these categories: //# Returns true if a codepoint belongs to any of these categories:
//# Nd, Nl //# Nd, Nl
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_number(char32_t c) noexcept constexpr bool is_non_ascii_number(char32_t c) noexcept
{ {
if (U'\u0660' > c || c > U'\U0001FBF9') if (U'\u0660' > c || c > U'\U0001FBF9')
@ -638,8 +623,7 @@ TOML_IMPL_NAMESPACE_START
//# Returns true if a codepoint belongs to any of these categories: //# Returns true if a codepoint belongs to any of these categories:
//# Mn, Mc //# Mn, Mc
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_combining_mark(char32_t c) noexcept constexpr bool is_combining_mark(char32_t c) noexcept
{ {
if (U'\u0300' > c || c > U'\U000E01EF') if (U'\u0300' > c || c > U'\U000E01EF')
@ -849,8 +833,7 @@ TOML_IMPL_NAMESPACE_START
#endif // TOML_LANG_UNRELEASED #endif // TOML_LANG_UNRELEASED
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_bare_key_character(char32_t codepoint) noexcept constexpr bool is_bare_key_character(char32_t codepoint) noexcept
{ {
return is_ascii_letter(codepoint) || is_decimal_digit(codepoint) || codepoint == U'-' || codepoint == U'_' return is_ascii_letter(codepoint) || is_decimal_digit(codepoint) || codepoint == U'-' || codepoint == U'_'
@ -861,8 +844,7 @@ TOML_IMPL_NAMESPACE_START
; ;
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_value_terminator(char32_t codepoint) noexcept constexpr bool is_value_terminator(char32_t codepoint) noexcept
{ {
return is_ascii_line_break(codepoint) || is_ascii_whitespace(codepoint) || codepoint == U']' return is_ascii_line_break(codepoint) || is_ascii_whitespace(codepoint) || codepoint == U']'
@ -870,22 +852,19 @@ TOML_IMPL_NAMESPACE_START
|| is_non_ascii_whitespace(codepoint); || is_non_ascii_whitespace(codepoint);
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_control_character(char32_t codepoint) noexcept constexpr bool is_control_character(char32_t codepoint) noexcept
{ {
return codepoint <= U'\u001F' || codepoint == U'\u007F'; return codepoint <= U'\u001F' || codepoint == U'\u007F';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_nontab_control_character(char32_t codepoint) noexcept constexpr bool is_nontab_control_character(char32_t codepoint) noexcept
{ {
return codepoint <= U'\u0008' || (codepoint >= U'\u000A' && codepoint <= U'\u001F') || codepoint == U'\u007F'; return codepoint <= U'\u0008' || (codepoint >= U'\u000A' && codepoint <= U'\u001F') || codepoint == U'\u007F';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept
{ {
return codepoint >= 0xD800u && codepoint <= 0xDFFF; return codepoint >= 0xD800u && codepoint <= 0xDFFF;
@ -917,13 +896,13 @@ TOML_IMPL_NAMESPACE_START
36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
}; };
TOML_NODISCARD TOML_PURE_INLINE_GETTER
constexpr bool error() const noexcept constexpr bool error() const noexcept
{ {
return state == uint_least32_t{ 12u }; return state == uint_least32_t{ 12u };
} }
TOML_NODISCARD TOML_PURE_INLINE_GETTER
constexpr bool has_code_point() const noexcept constexpr bool has_code_point() const noexcept
{ {
return state == uint_least32_t{}; return state == uint_least32_t{};
@ -947,6 +926,12 @@ TOML_IMPL_NAMESPACE_START
state = state_table[state + uint_least32_t{ 256u } + type]; state = state_table[state + uint_least32_t{ 256u } + type];
} }
TOML_ALWAYS_INLINE
constexpr void reset() noexcept
{
state = {};
}
}; };
} }
TOML_IMPL_NAMESPACE_END; TOML_IMPL_NAMESPACE_END;

View File

@ -2,8 +2,8 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> //# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#pragma once #pragma once
#include "date_time.h" #include "date_time.h"
#include "node.h" #include "node.h"
#include "print_to_stream.h" #include "print_to_stream.h"
@ -1105,7 +1105,7 @@ TOML_NAMESPACE_START
TOML_NAMESPACE_END; TOML_NAMESPACE_END;
/// \cond /// \cond
#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION
#include "value_extern.inl" #include "value_extern.inl"
#endif #endif
/// \endcond /// \endcond

View File

@ -14,7 +14,7 @@
#include "value.h" #include "value.h"
#include "header_start.h" #include "header_start.h"
#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION
#include "value_extern.inl" #include "value_extern.inl"
#endif // TOML_EXTERN_TEMPLATES #endif // TOML_EXTERN_TEMPLATES

View File

@ -2,7 +2,6 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> //# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#pragma once
/// \cond /// \cond
#include "value.h" #include "value.h"

351
toml.hpp
View File

@ -1197,10 +1197,14 @@ TOML_NAMESPACE_START // abi namespace
template <typename T> template <typename T>
struct TOML_TRIVIAL_ABI inserter struct TOML_TRIVIAL_ABI inserter
{ {
T&& value; static_assert(std::is_reference_v<T>);
T value;
}; };
template <typename T> template <typename T>
inserter(T &&) -> inserter<T>; inserter(T &&) -> inserter<T&&>;
template <typename T>
inserter(T&) -> inserter<T&>;
} }
TOML_NAMESPACE_END; TOML_NAMESPACE_END;
@ -3302,7 +3306,7 @@ TOML_NAMESPACE_START
} }
TOML_NAMESPACE_END; TOML_NAMESPACE_END;
#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION
TOML_NAMESPACE_START TOML_NAMESPACE_START
{ {
@ -4344,7 +4348,7 @@ TOML_NAMESPACE_START
} }
TOML_NAMESPACE_END; TOML_NAMESPACE_END;
#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION
TOML_NAMESPACE_START TOML_NAMESPACE_START
{ {
@ -4428,45 +4432,67 @@ TOML_IMPL_NAMESPACE_START
template <typename T> template <typename T>
TOML_NODISCARD TOML_NODISCARD
TOML_ATTR(returns_nonnull) TOML_ATTR(returns_nonnull)
auto* make_node_specialized(T && val) auto* make_node_specialized(T && val, [[maybe_unused]] value_flags flags)
{ {
using type = unwrap_node<remove_cvref<T>>; using unwrapped_type = unwrap_node<remove_cvref<T>>;
static_assert(!std::is_same_v<type, node>); static_assert(!std::is_same_v<unwrapped_type, node>);
static_assert(!is_node_view<type>); static_assert(!is_node_view<unwrapped_type>);
if constexpr (is_one_of<type, array, table>) // arrays + tables - invoke copy/move ctor
if constexpr (is_one_of<unwrapped_type, array, table>)
{ {
return new type{ static_cast<T&&>(val) }; return new unwrapped_type{ static_cast<T&&>(val) };
}
else if constexpr (is_native<type> && !std::is_same_v<remove_cvref<T>, type>)
{
return new value<type>{ static_cast<T&&>(val) };
} }
// values
else else
{ {
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT, using native_type = native_type_of<unwrapped_type>;
"Instantiating values from wide-character strings is only " using value_type = value<native_type>;
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
static_assert(is_native<type> || is_losslessly_convertible_to_native<type>,
"Value initializers must be (or be promotable to) one of the TOML value types");
using value_type = native_type_of<remove_cvref<T>>; value_type* out;
if constexpr (is_wide_string<T>)
// copy/move ctor
if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
{ {
#if TOML_WINDOWS_COMPAT out = new value_type{ static_cast<T&&>(val) };
return new value<value_type>{ narrow(static_cast<T&&>(val)) };
#else // only override the flags if the new ones are nonzero
static_assert(dependent_false<T>, "Evaluated unreachable branch!"); // (so the copy/move ctor does the right thing in the general case)
#endif if (flags != value_flags::none)
out->flags(flags);
} }
// creating from raw value
else else
return new value<value_type>{ static_cast<T&&>(val) }; {
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT,
"Instantiating values from wide-character strings is only "
"supported on Windows with TOML_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_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
out = new value_type{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
out = new value_type{ static_cast<T&&>(val) };
out->flags(flags);
}
return out;
} }
} }
template <typename T> template <typename T>
TOML_NODISCARD TOML_NODISCARD
auto* make_node(T && val) auto* make_node(T && val, value_flags flags = value_flags::none)
{ {
using type = unwrap_node<remove_cvref<T>>; using type = unwrap_node<remove_cvref<T>>;
if constexpr (std::is_same_v<type, node> || is_node_view<type>) if constexpr (std::is_same_v<type, node> || is_node_view<type>)
@ -4478,19 +4504,20 @@ TOML_IMPL_NAMESPACE_START
} }
return static_cast<T&&>(val).visit( return static_cast<T&&>(val).visit(
[](auto&& concrete) { [flags](auto&& concrete) {
return static_cast<toml::node*>(make_node_specialized(static_cast<decltype(concrete)&&>(concrete))); return static_cast<toml::node*>(
make_node_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
}); });
} }
else else
return make_node_specialized(static_cast<T&&>(val)); return make_node_specialized(static_cast<T&&>(val), flags);
} }
template <typename T> template <typename T>
TOML_NODISCARD TOML_NODISCARD
auto* make_node(inserter<T> && val) auto* make_node(inserter<T> && val, value_flags flags = value_flags::none)
{ {
return make_node(static_cast<T&&>(val.value)); return make_node(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>)> template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
@ -4717,14 +4744,14 @@ TOML_NAMESPACE_START
void preinsertion_resize(size_t idx, size_t count); void preinsertion_resize(size_t idx, size_t count);
template <typename T> template <typename T>
void emplace_back_if_not_empty_view(T&& val) void emplace_back_if_not_empty_view(T&& val, value_flags flags)
{ {
if constexpr (is_node_view<T>) if constexpr (is_node_view<T>)
{ {
if (!val) if (!val)
return; return;
} }
elements.emplace_back(impl::make_node(static_cast<T&&>(val))); elements.emplace_back(impl::make_node(static_cast<T&&>(val), flags));
} }
TOML_NODISCARD TOML_NODISCARD
@ -4786,10 +4813,10 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals) explicit array(ElemType&& val, ElemTypes&&... vals)
{ {
elements.reserve(sizeof...(ElemTypes) + 1u); elements.reserve(sizeof...(ElemTypes) + 1u);
emplace_back_if_not_empty_view(static_cast<ElemType&&>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), value_flags::none);
if constexpr (sizeof...(ElemTypes) > 0) if constexpr (sizeof...(ElemTypes) > 0)
{ {
(emplace_back_if_not_empty_view(static_cast<ElemTypes&&>(vals)), ...); (emplace_back_if_not_empty_view(static_cast<ElemTypes&&>(vals), value_flags::none), ...);
} }
#if TOML_LIFETIME_HOOKS #if TOML_LIFETIME_HOOKS
@ -4964,18 +4991,18 @@ TOML_NAMESPACE_START
} }
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, ElemType&& val) iterator insert(const_iterator pos, ElemType&& val, value_flags flags = value_flags::none)
{ {
if constexpr (is_node_view<ElemType>) if constexpr (is_node_view<ElemType>)
{ {
if (!val) if (!val)
return end(); return end();
} }
return { elements.emplace(pos.raw_, impl::make_node(static_cast<ElemType&&>(val))) }; return { elements.emplace(pos.raw_, impl::make_node(static_cast<ElemType&&>(val), flags)) };
} }
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, size_t count, ElemType&& val) iterator insert(const_iterator pos, size_t count, ElemType&& val, value_flags flags = value_flags::none)
{ {
if constexpr (is_node_view<ElemType>) if constexpr (is_node_view<ElemType>)
{ {
@ -4985,23 +5012,23 @@ TOML_NAMESPACE_START
switch (count) switch (count)
{ {
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, static_cast<ElemType&&>(val)); case 1: return insert(pos, static_cast<ElemType&&>(val), flags);
default: default:
{ {
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin()); const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, count); preinsertion_resize(start_idx, count);
size_t i = start_idx; size_t i = start_idx;
for (size_t e = start_idx + count - 1u; i < e; i++) for (size_t e = start_idx + count - 1u; i < e; i++)
elements[i].reset(impl::make_node(val)); elements[i].reset(impl::make_node(val, flags));
elements[i].reset(impl::make_node(static_cast<ElemType&&>(val))); elements[i].reset(impl::make_node(static_cast<ElemType&&>(val), flags));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
} }
} }
template <typename Iter> template <typename Iter>
iterator insert(const_iterator pos, Iter first, Iter last) iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags = value_flags::none)
{ {
const auto distance = std::distance(first, last); const auto distance = std::distance(first, last);
if (distance <= 0) if (distance <= 0)
@ -5029,18 +5056,20 @@ TOML_NAMESPACE_START
continue; continue;
} }
if constexpr (std::is_rvalue_reference_v<deref_type>) if constexpr (std::is_rvalue_reference_v<deref_type>)
elements[i++].reset(impl::make_node(std::move(*it))); elements[i++].reset(impl::make_node(std::move(*it), flags));
else else
elements[i++].reset(impl::make_node(*it)); elements[i++].reset(impl::make_node(*it, flags));
} }
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
} }
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) iterator insert(const_iterator pos,
std::initializer_list<ElemType> ilist,
value_flags flags = value_flags::none)
{ {
return insert(pos, ilist.begin(), ilist.end()); return insert(pos, ilist.begin(), ilist.end(), flags);
} }
template <typename ElemType, typename... Args> template <typename ElemType, typename... Args>
@ -5084,9 +5113,9 @@ TOML_NAMESPACE_START
} }
template <typename ElemType> template <typename ElemType>
void push_back(ElemType&& val) void push_back(ElemType&& val, value_flags flags = value_flags::none)
{ {
emplace_back_if_not_empty_view(static_cast<ElemType&&>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
} }
template <typename ElemType, typename... Args> template <typename ElemType, typename... Args>
@ -5374,46 +5403,46 @@ TOML_IMPL_NAMESPACE_START
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::string&& k, V&& v) // table_init_pair(std::string&& k, V&& v, value_flags flags = value_flags::none) //
: key{ std::move(k) }, : key{ std::move(k) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::string_view k, V&& v) // table_init_pair(std::string_view k, V&& v, value_flags flags = value_flags::none) //
: key{ k }, : key{ k },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(const char* k, V&& v) // table_init_pair(const char* k, V&& v, value_flags flags = value_flags::none) //
: key{ k }, : key{ k },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::wstring&& k, V&& v) // table_init_pair(std::wstring&& k, V&& v, value_flags flags = value_flags::none) //
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(std::wstring_view k, V&& v) // table_init_pair(std::wstring_view k, V&& v, value_flags flags = value_flags::none) //
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
template <typename V> template <typename V>
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
table_init_pair(const wchar_t* k, V&& v) // table_init_pair(const wchar_t* k, V&& v, value_flags flags = value_flags::none) //
: key{ narrow(std::wstring_view{ k }) }, : key{ narrow(std::wstring_view{ k }) },
value{ make_node(static_cast<V&&>(v)) } value{ make_node(static_cast<V&&>(v), flags) }
{} {}
#endif #endif
@ -5671,7 +5700,7 @@ TOML_NAMESPACE_START
TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v<KeyType&&, std::string_view> || impl::is_wide_string<KeyType>), TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v<KeyType&&, std::string_view> || impl::is_wide_string<KeyType>),
typename KeyType, typename KeyType,
typename ValueType) typename ValueType)
std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val) std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val, value_flags flags = value_flags::none)
{ {
static_assert( static_assert(
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT, !impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
@ -5686,7 +5715,7 @@ TOML_NAMESPACE_START
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
return insert(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val)); return insert(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val), flags);
#else #else
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!"); static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif #endif
@ -5698,7 +5727,7 @@ TOML_NAMESPACE_START
{ {
ipos = map_.emplace_hint(ipos, ipos = map_.emplace_hint(ipos,
std::forward<KeyType>(key), std::forward<KeyType>(key),
impl::make_node(std::forward<ValueType>(val))); impl::make_node(std::forward<ValueType>(val), flags));
return { iterator{ ipos }, true }; return { iterator{ ipos }, true };
} }
return { iterator{ ipos }, false }; return { iterator{ ipos }, false };
@ -5707,21 +5736,23 @@ TOML_NAMESPACE_START
TOML_CONSTRAINED_TEMPLATE((!std::is_convertible_v<Iter, std::string_view> && !impl::is_wide_string<Iter>), TOML_CONSTRAINED_TEMPLATE((!std::is_convertible_v<Iter, std::string_view> && !impl::is_wide_string<Iter>),
typename Iter) typename Iter)
void insert(Iter first, Iter last) void insert(Iter first, Iter last, value_flags flags = value_flags::none)
{ {
if (first == last) if (first == last)
return; return;
for (auto it = first; it != last; it++) for (auto it = first; it != last; it++)
{ {
if constexpr (std::is_rvalue_reference_v<decltype(*it)>) if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
insert(std::move((*it).first), std::move((*it).second)); insert(std::move((*it).first), std::move((*it).second), flags);
else else
insert((*it).first, (*it).second); insert((*it).first, (*it).second, flags);
} }
} }
template <typename KeyType, typename ValueType> template <typename KeyType, typename ValueType>
std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val) std::pair<iterator, bool> insert_or_assign(KeyType&& key,
ValueType&& val,
value_flags flags = value_flags::none)
{ {
static_assert( static_assert(
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT, !impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
@ -5736,7 +5767,7 @@ TOML_NAMESPACE_START
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
return insert_or_assign(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val)); return insert_or_assign(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val), flags);
#else #else
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!"); static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif #endif
@ -5748,12 +5779,12 @@ TOML_NAMESPACE_START
{ {
ipos = map_.emplace_hint(ipos, ipos = map_.emplace_hint(ipos,
std::forward<KeyType>(key), std::forward<KeyType>(key),
impl::make_node(std::forward<ValueType>(val))); impl::make_node(std::forward<ValueType>(val), flags));
return { iterator{ ipos }, true }; return { iterator{ ipos }, true };
} }
else else
{ {
(*ipos).second.reset(impl::make_node(std::forward<ValueType>(val))); (*ipos).second.reset(impl::make_node(std::forward<ValueType>(val), flags));
return { iterator{ ipos }, false }; return { iterator{ ipos }, false };
} }
} }
@ -5966,15 +5997,13 @@ TOML_DISABLE_SWITCH_WARNINGS;
TOML_IMPL_NAMESPACE_START TOML_IMPL_NAMESPACE_START
{ {
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
{ {
return codepoint == U'\t' || codepoint == U' '; return codepoint == U'\t' || codepoint == U' ';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept
{ {
// see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode // see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
@ -5989,24 +6018,21 @@ TOML_IMPL_NAMESPACE_START
; ;
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_whitespace(char32_t codepoint) noexcept constexpr bool is_whitespace(char32_t codepoint) noexcept
{ {
return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint); return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint);
} }
template <bool IncludeCarriageReturn = true> template <bool IncludeCarriageReturn = true>
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_ascii_line_break(char32_t codepoint) noexcept constexpr bool is_ascii_line_break(char32_t codepoint) noexcept
{ {
constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f'; constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f';
return (codepoint >= U'\n' && codepoint <= low_range_end); return (codepoint >= U'\n' && codepoint <= low_range_end);
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept
{ {
// see https://en.wikipedia.org/wiki/Whitespace_character#Unicode // see https://en.wikipedia.org/wiki/Whitespace_character#Unicode
@ -6019,58 +6045,50 @@ TOML_IMPL_NAMESPACE_START
} }
template <bool IncludeCarriageReturn = true> template <bool IncludeCarriageReturn = true>
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_line_break(char32_t codepoint) noexcept constexpr bool is_line_break(char32_t codepoint) noexcept
{ {
return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_non_ascii_line_break(codepoint); return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_non_ascii_line_break(codepoint);
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_string_delimiter(char32_t codepoint) noexcept constexpr bool is_string_delimiter(char32_t codepoint) noexcept
{ {
return codepoint == U'"' || codepoint == U'\''; return codepoint == U'"' || codepoint == U'\'';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_ascii_letter(char32_t codepoint) noexcept constexpr bool is_ascii_letter(char32_t codepoint) noexcept
{ {
return (codepoint >= U'a' && codepoint <= U'z') || (codepoint >= U'A' && codepoint <= U'Z'); return (codepoint >= U'a' && codepoint <= U'z') || (codepoint >= U'A' && codepoint <= U'Z');
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_binary_digit(char32_t codepoint) noexcept constexpr bool is_binary_digit(char32_t codepoint) noexcept
{ {
return codepoint == U'0' || codepoint == U'1'; return codepoint == U'0' || codepoint == U'1';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_octal_digit(char32_t codepoint) noexcept constexpr bool is_octal_digit(char32_t codepoint) noexcept
{ {
return (codepoint >= U'0' && codepoint <= U'7'); return (codepoint >= U'0' && codepoint <= U'7');
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_decimal_digit(char32_t codepoint) noexcept constexpr bool is_decimal_digit(char32_t codepoint) noexcept
{ {
return (codepoint >= U'0' && codepoint <= U'9'); return (codepoint >= U'0' && codepoint <= U'9');
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_hexadecimal_digit(char32_t c) noexcept constexpr bool is_hexadecimal_digit(char32_t c) noexcept
{ {
return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull; return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull;
} }
template <typename T> template <typename T>
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr uint_least32_t hex_to_dec(const T codepoint) noexcept constexpr uint_least32_t hex_to_dec(const T codepoint) noexcept
{ {
if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>) if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
@ -6084,8 +6102,7 @@ TOML_IMPL_NAMESPACE_START
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys) #if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_letter(char32_t c) noexcept constexpr bool is_non_ascii_letter(char32_t c) noexcept
{ {
if (U'\xAA' > c || c > U'\U0003134A') if (U'\xAA' > c || c > U'\U0003134A')
@ -6436,8 +6453,7 @@ TOML_IMPL_NAMESPACE_START
TOML_UNREACHABLE; TOML_UNREACHABLE;
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_non_ascii_number(char32_t c) noexcept constexpr bool is_non_ascii_number(char32_t c) noexcept
{ {
if (U'\u0660' > c || c > U'\U0001FBF9') if (U'\u0660' > c || c > U'\U0001FBF9')
@ -6588,8 +6604,7 @@ TOML_IMPL_NAMESPACE_START
TOML_UNREACHABLE; TOML_UNREACHABLE;
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_combining_mark(char32_t c) noexcept constexpr bool is_combining_mark(char32_t c) noexcept
{ {
if (U'\u0300' > c || c > U'\U000E01EF') if (U'\u0300' > c || c > U'\U000E01EF')
@ -6799,8 +6814,7 @@ TOML_IMPL_NAMESPACE_START
#endif // TOML_LANG_UNRELEASED #endif // TOML_LANG_UNRELEASED
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_bare_key_character(char32_t codepoint) noexcept constexpr bool is_bare_key_character(char32_t codepoint) noexcept
{ {
return is_ascii_letter(codepoint) || is_decimal_digit(codepoint) || codepoint == U'-' || codepoint == U'_' return is_ascii_letter(codepoint) || is_decimal_digit(codepoint) || codepoint == U'-' || codepoint == U'_'
@ -6811,8 +6825,7 @@ TOML_IMPL_NAMESPACE_START
; ;
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_value_terminator(char32_t codepoint) noexcept constexpr bool is_value_terminator(char32_t codepoint) noexcept
{ {
return is_ascii_line_break(codepoint) || is_ascii_whitespace(codepoint) || codepoint == U']' return is_ascii_line_break(codepoint) || is_ascii_whitespace(codepoint) || codepoint == U']'
@ -6820,22 +6833,19 @@ TOML_IMPL_NAMESPACE_START
|| is_non_ascii_whitespace(codepoint); || is_non_ascii_whitespace(codepoint);
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_control_character(char32_t codepoint) noexcept constexpr bool is_control_character(char32_t codepoint) noexcept
{ {
return codepoint <= U'\u001F' || codepoint == U'\u007F'; return codepoint <= U'\u001F' || codepoint == U'\u007F';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_nontab_control_character(char32_t codepoint) noexcept constexpr bool is_nontab_control_character(char32_t codepoint) noexcept
{ {
return codepoint <= U'\u0008' || (codepoint >= U'\u000A' && codepoint <= U'\u001F') || codepoint == U'\u007F'; return codepoint <= U'\u0008' || (codepoint >= U'\u000A' && codepoint <= U'\u001F') || codepoint == U'\u007F';
} }
TOML_NODISCARD TOML_CONST_GETTER
TOML_ATTR(const)
constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept
{ {
return codepoint >= 0xD800u && codepoint <= 0xDFFF; return codepoint >= 0xD800u && codepoint <= 0xDFFF;
@ -6866,13 +6876,13 @@ TOML_IMPL_NAMESPACE_START
36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
}; };
TOML_NODISCARD TOML_PURE_INLINE_GETTER
constexpr bool error() const noexcept constexpr bool error() const noexcept
{ {
return state == uint_least32_t{ 12u }; return state == uint_least32_t{ 12u };
} }
TOML_NODISCARD TOML_PURE_INLINE_GETTER
constexpr bool has_code_point() const noexcept constexpr bool has_code_point() const noexcept
{ {
return state == uint_least32_t{}; return state == uint_least32_t{};
@ -6896,6 +6906,12 @@ TOML_IMPL_NAMESPACE_START
state = state_table[state + uint_least32_t{ 256u } + type]; state = state_table[state + uint_least32_t{ 256u } + type];
} }
TOML_ALWAYS_INLINE
constexpr void reset() noexcept
{
state = {};
}
}; };
} }
TOML_IMPL_NAMESPACE_END; TOML_IMPL_NAMESPACE_END;
@ -7412,14 +7428,16 @@ TOML_IMPL_NAMESPACE_START
format_flags flags_; // format_flags flags_; //
int indent_; // these are set in attach() int indent_; // these are set in attach()
bool naked_newline_; // bool naked_newline_; //
std::string_view indent_string_;
size_t indent_columns_;
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
const parse_result* result_ = {}; const parse_result* result_ = {};
#endif #endif
protected: TOML_API
static constexpr size_t indent_columns = 4; void set_indent_string(std::string_view str) noexcept;
static constexpr std::string_view indent_string = " "sv;
protected:
TOML_PURE_INLINE_GETTER TOML_PURE_INLINE_GETTER
const toml::node& source() const noexcept const toml::node& source() const noexcept
{ {
@ -7453,6 +7471,12 @@ TOML_IMPL_NAMESPACE_START
indent_--; indent_--;
} }
TOML_PURE_INLINE_GETTER
size_t indent_columns() const noexcept
{
return indent_columns_;
}
TOML_PURE_INLINE_GETTER TOML_PURE_INLINE_GETTER
bool indent_array_elements() const noexcept bool indent_array_elements() const noexcept
{ {
@ -7541,19 +7565,21 @@ TOML_IMPL_NAMESPACE_START
TOML_NODISCARD TOML_NODISCARD
TOML_API TOML_API
bool dump_failed_parse_result() noexcept(!TOML_PARSER || TOML_EXCEPTIONS); bool dump_failed_parse_result();
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
formatter(const toml::node& source, format_flags flags) noexcept // formatter(const toml::node& source, format_flags flags, std::string_view indent) noexcept //
: source_{ &source }, : source_{ &source },
flags_{ flags } flags_{ flags }
{} {
set_indent_string(indent);
}
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
TOML_API TOML_API
formatter(const parse_result& result, format_flags flags) noexcept; formatter(const parse_result& result, format_flags flags, std::string_view indent) noexcept;
#endif #endif
}; };
@ -7625,14 +7651,14 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, (flags | mandatory_flags) & ~ignored_flags } : base{ source, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS) #if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit default_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept explicit default_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ result, (flags | mandatory_flags) & ~ignored_flags } : base{ result, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#endif #endif
@ -7690,14 +7716,14 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, (flags | mandatory_flags) & ~ignored_flags } : base{ source, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS) #if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ result, (flags | mandatory_flags) & ~ignored_flags } : base{ result, (flags | mandatory_flags) & ~ignored_flags, " "sv }
{} {}
#endif #endif
@ -8316,7 +8342,7 @@ TOML_PUSH_WARNINGS;
TOML_DISABLE_SPAM_WARNINGS; TOML_DISABLE_SPAM_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS; TOML_DISABLE_SWITCH_WARNINGS;
#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION
TOML_NAMESPACE_START TOML_NAMESPACE_START
{ {
@ -8390,7 +8416,7 @@ TOML_PUSH_WARNINGS;
TOML_DISABLE_SPAM_WARNINGS; TOML_DISABLE_SPAM_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS; TOML_DISABLE_SWITCH_WARNINGS;
#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE #if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION
TOML_NAMESPACE_START TOML_NAMESPACE_START
{ {
@ -12498,14 +12524,25 @@ TOML_IMPL_NAMESPACE_START
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
formatter::formatter(const parse_result& result, format_flags flags) noexcept // formatter::formatter(const parse_result& result, format_flags flags, std::string_view indent) noexcept //
: source_{ result ? &result.table() : nullptr }, : source_{ result ? &result.table() : nullptr },
flags_{ flags }, flags_{ flags },
result_{ &result } result_{ &result }
{} {
set_indent_string(indent);
}
#endif #endif
TOML_EXTERNAL_LINKAGE
void formatter::set_indent_string(std::string_view str) noexcept
{
indent_string_ = str.data() ? str : " "sv;
indent_columns_ = {};
for (auto c : indent_string_)
indent_columns_ += c == '\t' ? 4u : 1u;
}
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
void formatter::attach(std::ostream & stream) noexcept void formatter::attach(std::ostream & stream) noexcept
{ {
@ -12535,7 +12572,7 @@ TOML_IMPL_NAMESPACE_START
{ {
for (int i = 0; i < indent_; i++) for (int i = 0; i < indent_; i++)
{ {
print_to_stream(*stream_, indent_string); print_to_stream(*stream_, indent_string_);
naked_newline_ = false; naked_newline_ = false;
} }
} }
@ -12689,7 +12726,7 @@ TOML_IMPL_NAMESPACE_START
#if TOML_PARSER && !TOML_EXCEPTIONS #if TOML_PARSER && !TOML_EXCEPTIONS
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
bool formatter::dump_failed_parse_result() noexcept(false) bool formatter::dump_failed_parse_result()
{ {
if (result_ && !(*result_)) if (result_ && !(*result_))
{ {
@ -12703,7 +12740,7 @@ TOML_IMPL_NAMESPACE_START
TOML_EXTERNAL_LINKAGE TOML_EXTERNAL_LINKAGE
TOML_ATTR(const) TOML_ATTR(const)
bool formatter::dump_failed_parse_result() noexcept(true) bool formatter::dump_failed_parse_result()
{ {
return false; return false;
} }
@ -12774,11 +12811,11 @@ TOML_NAMESPACE_START
{ {
case node_type::table: case node_type::table:
{ {
auto& n = *reinterpret_cast<const table*>(&node); auto& tbl = *reinterpret_cast<const table*>(&node);
if (n.empty()) if (tbl.empty())
return 2u; // "{}" return 2u; // "{}"
size_t weight = 3u; // "{ }" size_t weight = 3u; // "{ }"
for (auto&& [k, v] : n) for (auto&& [k, v] : tbl)
{ {
weight += k.length() + count_inline_columns(v) + 2u; // + ", " weight += k.length() + count_inline_columns(v) + 2u; // + ", "
if (weight >= line_wrap_cols) if (weight >= line_wrap_cols)
@ -12789,11 +12826,11 @@ TOML_NAMESPACE_START
case node_type::array: case node_type::array:
{ {
auto& n = *reinterpret_cast<const array*>(&node); auto& arr = *reinterpret_cast<const array*>(&node);
if (n.empty()) if (arr.empty())
return 2u; // "[]" return 2u; // "[]"
size_t weight = 3u; // "[ ]" size_t weight = 3u; // "[ ]"
for (auto& elem : n) for (auto& elem : arr)
{ {
weight += count_inline_columns(elem) + 2u; // + ", " weight += count_inline_columns(elem) + 2u; // + ", "
if (weight >= line_wrap_cols) if (weight >= line_wrap_cols)
@ -12804,38 +12841,38 @@ TOML_NAMESPACE_START
case node_type::string: case node_type::string:
{ {
auto& n = *reinterpret_cast<const value<std::string>*>(&node); // todo: proper utf8 decoding?
return n.get().length() + 2u; // + "" // todo: tab awareness?
auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
return str.length() + 2u; // + ""
} }
case node_type::integer: case node_type::integer:
{ {
auto& n = *reinterpret_cast<const value<int64_t>*>(&node); auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
auto v = n.get(); if (!val)
if (!v)
return 1u; return 1u;
size_t weight = {}; size_t weight = {};
if (v < 0) if (val < 0)
{ {
weight += 1u; weight += 1u;
v *= -1; val *= -1;
} }
return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1u; return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
} }
case node_type::floating_point: case node_type::floating_point:
{ {
auto& n = *reinterpret_cast<const value<double>*>(&node); auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
auto v = n.get(); if (val == 0.0)
if (v == 0.0)
return 3u; // "0.0" return 3u; // "0.0"
size_t weight = 2u; // ".0" size_t weight = 2u; // ".0"
if (v < 0.0) if (val < 0.0)
{ {
weight += 1u; weight += 1u;
v *= -1.0; val *= -1.0;
} }
return weight + static_cast<size_t>(log10(v)) + 1u; return weight + static_cast<size_t>(log10(val)) + 1u;
break; break;
} }
@ -12953,9 +12990,9 @@ TOML_NAMESPACE_START
else else
{ {
const auto original_indent = base::indent(); const auto original_indent = base::indent();
const auto multiline = const auto multiline = forces_multiline(
forces_multiline(arr, arr,
base::indent_columns * static_cast<size_t>(original_indent < 0 ? 0 : original_indent)); base::indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
impl::print_to_stream(base::stream(), "["sv); impl::print_to_stream(base::stream(), "["sv);
if (multiline) if (multiline)
{ {

View File

@ -16,15 +16,10 @@ from io import StringIO
class Preprocessor: class Preprocessor:
__re_includes = re.compile(r'^\s*#\s*include\s+"(.+?)".*?$', re.I | re.M) __re_includes = re.compile(r'^\s*#\s*include\s+"(.+?)".*?$', re.I | re.M)
__multiples_allowed = [ __re_pragma_once = re.compile(r'^\s*#\s*pragma\s+once\s*$', re.M)
r'impl/header_start.h',
r'impl/header_end.h',
r'impl/value_extern.inl',
r'impl/node_view_extern.inl',
]
def __init__(self, file): def __init__(self, file):
self.__processed_includes = set() self.__once_only = set()
self.__current_level = 0 self.__current_level = 0
self.__directory_stack = [ Path.cwd() ] self.__directory_stack = [ Path.cwd() ]
self.__entry_root = '' self.__entry_root = ''
@ -38,27 +33,30 @@ class Preprocessor:
incl = Path(incl.strip().replace('\\',r'/')) incl = Path(incl.strip().replace('\\',r'/'))
if not incl.is_absolute(): if not incl.is_absolute():
incl = Path(self.__directory_stack[-1], incl).resolve() incl = Path(self.__directory_stack[-1], incl).resolve()
if self.__current_level == 0 and self.__entry_root == '': if incl in self.__once_only:
self.__entry_root = str(incl.parent).replace('\\',r'/')
relative_path = str(incl).replace('\\',r'/')
if relative_path.startswith(self.__entry_root):
relative_path = relative_path[len(self.__entry_root):].strip('/')
if incl in self.__processed_includes and relative_path not in self.__multiples_allowed:
return '' return ''
self.__processed_includes.add(incl)
self.__directory_stack.append(incl.parent)
text = utils.read_all_text_from_file(incl, logger=True).strip() + '\n' text = utils.read_all_text_from_file(incl, logger=True).strip() + '\n'
text = text.replace('\r\n', '\n') # convert windows newlines text = text.replace('\r\n', '\n') # convert windows newlines
self.__directory_stack.append(incl.parent)
if self.__re_pragma_once.search(text):
self.__once_only.add(incl)
if self.__current_level == 0 and self.__entry_root == '':
self.__entry_root = str(incl.parent).replace('\\',r'/')
if self.__current_level > 0:
text = self.__re_pragma_once.sub('', text)
self.__current_level += 1 self.__current_level += 1
text = self.__re_includes.sub(lambda m : self.__preprocess(m), text, 0) text = self.__re_includes.sub(lambda m : self.__preprocess(m), text, 0)
self.__current_level -= 1 self.__current_level -= 1
if self.__current_level == 1: if self.__current_level == 1:
header = utils.make_divider(relative_path, 10, pattern = r'*') header = str(incl).replace('\\',r'/')
if header.startswith(self.__entry_root):
header = header[len(self.__entry_root):].strip('/')
header = utils.make_divider(header, 10, pattern = r'*')
text = f'\n\n{header}\n\n{text}' text = f'\n\n{header}\n\n{text}'
self.__directory_stack.pop() self.__directory_stack.pop()
@ -80,8 +78,6 @@ def main():
# strip various things: # strip various things:
if 1: if 1:
# 'pragma once'
toml_h = re.sub(r'^\s*#\s*pragma\s+once\s*$', '', toml_h, 0, re.I | re.M)
# trailing whitespace # trailing whitespace
toml_h = re.sub('([^ \t])[ \t]+\n', r'\1\n', toml_h) toml_h = re.sub('([^ \t])[ \t]+\n', r'\1\n', toml_h)
# explicit 'strip this' blocks # explicit 'strip this' blocks