From 1bf09fe500f7eeef41ae5f432f77a18fe6df1f40 Mon Sep 17 00:00:00 2001 From: Mark Gillard Date: Fri, 29 Oct 2021 11:12:41 +0300 Subject: [PATCH] added value flags to array + table insert methods (closes #44) also: - made single header generation script `#pragma once`-aware --- include/toml++/impl/array.h | 56 +++- include/toml++/impl/default_formatter.h | 4 +- include/toml++/impl/default_formatter.inl | 46 +-- include/toml++/impl/formatter.h | 24 +- include/toml++/impl/formatter.inl | 21 +- include/toml++/impl/forward_declarations.h | 8 +- include/toml++/impl/json_formatter.h | 4 +- include/toml++/impl/make_node.h | 81 +++-- include/toml++/impl/node_view.h | 4 +- include/toml++/impl/node_view.inl | 2 +- include/toml++/impl/node_view_extern.inl | 1 - include/toml++/impl/table.h | 58 ++-- include/toml++/impl/utf8.h | 73 ++--- include/toml++/impl/value.h | 4 +- include/toml++/impl/value.inl | 2 +- include/toml++/impl/value_extern.inl | 1 - toml.hpp | 351 ++++++++++++--------- tools/generate_single_header.py | 36 +-- 18 files changed, 438 insertions(+), 338 deletions(-) diff --git a/include/toml++/impl/array.h b/include/toml++/impl/array.h index 68ccc87..141aabb 100644 --- a/include/toml++/impl/array.h +++ b/include/toml++/impl/array.h @@ -255,14 +255,14 @@ TOML_NAMESPACE_START void preinsertion_resize(size_t idx, size_t count); template - 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) { if (!val) return; } - elements.emplace_back(impl::make_node(static_cast(val))); + elements.emplace_back(impl::make_node(static_cast(val), flags)); } TOML_NODISCARD @@ -364,10 +364,10 @@ TOML_NAMESPACE_START explicit array(ElemType&& val, ElemTypes&&... vals) { elements.reserve(sizeof...(ElemTypes) + 1u); - emplace_back_if_not_empty_view(static_cast(val)); + emplace_back_if_not_empty_view(static_cast(val), value_flags::none); if constexpr (sizeof...(ElemTypes) > 0) { - (emplace_back_if_not_empty_view(static_cast(vals)), ...); + (emplace_back_if_not_empty_view(static_cast(vals), value_flags::none), ...); } #if TOML_LIFETIME_HOOKS @@ -586,6 +586,10 @@ TOML_NAMESPACE_START /// (or a type promotable to one). /// \param pos The insertion position. /// \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} /// 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, /// because no insertion can take place. This is the only circumstance in which this can occur. template - 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) { if (!val) return end(); } - return { elements.emplace(pos.raw_, impl::make_node(static_cast(val))) }; + return { elements.emplace(pos.raw_, impl::make_node(static_cast(val), flags)) }; } /// \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 count The number of times the node or value should be 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} /// 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, /// because no insertion can take place. This is the only circumstance in which this can occur. template - 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) { @@ -653,17 +661,17 @@ TOML_NAMESPACE_START switch (count) { case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; - case 1: return insert(pos, static_cast(val)); + case 1: return insert(pos, static_cast(val), flags); default: { const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); preinsertion_resize(start_idx, count); size_t i = start_idx; 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 - elements[i].reset(impl::make_node(static_cast(val))); + elements[i].reset(impl::make_node(static_cast(val), flags)); return { elements.begin() + static_cast(start_idx) }; } } @@ -675,6 +683,10 @@ TOML_NAMESPACE_START /// \param pos The insertion position. /// \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 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} /// 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} /// A copy of pos template - 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); if (distance <= 0) @@ -711,9 +723,9 @@ TOML_NAMESPACE_START continue; } if constexpr (std::is_rvalue_reference_v) - elements[i++].reset(impl::make_node(std::move(*it))); + elements[i++].reset(impl::make_node(std::move(*it), flags)); else - elements[i++].reset(impl::make_node(*it)); + elements[i++].reset(impl::make_node(*it, flags)); } return { elements.begin() + static_cast(start_idx) }; } @@ -725,6 +737,10 @@ TOML_NAMESPACE_START /// (or a type promotable to one). /// \param pos The insertion position. /// \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} /// 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} /// A copy of pos template - iterator insert(const_iterator pos, std::initializer_list ilist) + iterator insert(const_iterator pos, + std::initializer_list 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. @@ -908,13 +926,17 @@ TOML_NAMESPACE_START /// /// \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 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. /// This is the only circumstance in which this can occur. template - void push_back(ElemType&& val) + void push_back(ElemType&& val, value_flags flags = value_flags::none) { - emplace_back_if_not_empty_view(static_cast(val)); + emplace_back_if_not_empty_view(static_cast(val), flags); } /// \brief Emplaces a new element at the end of the array. diff --git a/include/toml++/impl/default_formatter.h b/include/toml++/impl/default_formatter.h index b9dedde..bf592cd 100644 --- a/include/toml++/impl/default_formatter.h +++ b/include/toml++/impl/default_formatter.h @@ -99,7 +99,7 @@ TOML_NAMESPACE_START /// \param flags Format option flags. TOML_NODISCARD_CTOR 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) @@ -128,7 +128,7 @@ TOML_NAMESPACE_START /// \param flags Format option flags. TOML_NODISCARD_CTOR 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 diff --git a/include/toml++/impl/default_formatter.inl b/include/toml++/impl/default_formatter.inl index a201c61..5911c17 100644 --- a/include/toml++/impl/default_formatter.inl +++ b/include/toml++/impl/default_formatter.inl @@ -73,11 +73,11 @@ TOML_NAMESPACE_START { case node_type::table: { - auto& n = *reinterpret_cast(&node); - if (n.empty()) + auto& tbl = *reinterpret_cast(&node); + if (tbl.empty()) return 2u; // "{}" size_t weight = 3u; // "{ }" - for (auto&& [k, v] : n) + for (auto&& [k, v] : tbl) { weight += k.length() + count_inline_columns(v) + 2u; // + ", " if (weight >= line_wrap_cols) @@ -88,11 +88,11 @@ TOML_NAMESPACE_START case node_type::array: { - auto& n = *reinterpret_cast(&node); - if (n.empty()) + auto& arr = *reinterpret_cast(&node); + if (arr.empty()) return 2u; // "[]" size_t weight = 3u; // "[ ]" - for (auto& elem : n) + for (auto& elem : arr) { weight += count_inline_columns(elem) + 2u; // + ", " if (weight >= line_wrap_cols) @@ -103,38 +103,38 @@ TOML_NAMESPACE_START case node_type::string: { - auto& n = *reinterpret_cast*>(&node); - return n.get().length() + 2u; // + "" + // todo: proper utf8 decoding? + // todo: tab awareness? + auto& str = (*reinterpret_cast*>(&node)).get(); + return str.length() + 2u; // + "" } case node_type::integer: { - auto& n = *reinterpret_cast*>(&node); - auto v = n.get(); - if (!v) + auto val = (*reinterpret_cast*>(&node)).get(); + if (!val) return 1u; size_t weight = {}; - if (v < 0) + if (val < 0) { weight += 1u; - v *= -1; + val *= -1; } - return weight + static_cast(log10(static_cast(v))) + 1u; + return weight + static_cast(log10(static_cast(val))) + 1u; } case node_type::floating_point: { - auto& n = *reinterpret_cast*>(&node); - auto v = n.get(); - if (v == 0.0) + auto val = (*reinterpret_cast*>(&node)).get(); + if (val == 0.0) return 3u; // "0.0" size_t weight = 2u; // ".0" - if (v < 0.0) + if (val < 0.0) { weight += 1u; - v *= -1.0; + val *= -1.0; } - return weight + static_cast(log10(v)) + 1u; + return weight + static_cast(log10(val)) + 1u; break; } @@ -252,9 +252,9 @@ TOML_NAMESPACE_START else { const auto original_indent = base::indent(); - const auto multiline = - forces_multiline(arr, - base::indent_columns * static_cast(original_indent < 0 ? 0 : original_indent)); + const auto multiline = forces_multiline( + arr, + base::indent_columns() * static_cast(original_indent < 0 ? 0 : original_indent)); impl::print_to_stream(base::stream(), "["sv); if (multiline) { diff --git a/include/toml++/impl/formatter.h b/include/toml++/impl/formatter.h index d753934..f6ac823 100644 --- a/include/toml++/impl/formatter.h +++ b/include/toml++/impl/formatter.h @@ -19,14 +19,16 @@ TOML_IMPL_NAMESPACE_START format_flags flags_; // int indent_; // these are set in attach() bool naked_newline_; // + std::string_view indent_string_; + size_t indent_columns_; #if TOML_PARSER && !TOML_EXCEPTIONS const parse_result* result_ = {}; #endif - protected: - static constexpr size_t indent_columns = 4; - static constexpr std::string_view indent_string = " "sv; + TOML_API + void set_indent_string(std::string_view str) noexcept; + protected: TOML_PURE_INLINE_GETTER const toml::node& source() const noexcept { @@ -60,6 +62,12 @@ TOML_IMPL_NAMESPACE_START indent_--; } + TOML_PURE_INLINE_GETTER + size_t indent_columns() const noexcept + { + return indent_columns_; + } + TOML_PURE_INLINE_GETTER bool indent_array_elements() const noexcept { @@ -148,19 +156,21 @@ TOML_IMPL_NAMESPACE_START TOML_NODISCARD TOML_API - bool dump_failed_parse_result() noexcept(!TOML_PARSER || TOML_EXCEPTIONS); + bool dump_failed_parse_result(); 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 }, flags_{ flags } - {} + { + set_indent_string(indent); + } #if TOML_PARSER && !TOML_EXCEPTIONS TOML_NODISCARD_CTOR 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 }; diff --git a/include/toml++/impl/formatter.inl b/include/toml++/impl/formatter.inl index 94f88c5..558c95e 100644 --- a/include/toml++/impl/formatter.inl +++ b/include/toml++/impl/formatter.inl @@ -25,14 +25,25 @@ TOML_IMPL_NAMESPACE_START #if TOML_PARSER && !TOML_EXCEPTIONS 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 }, flags_{ flags }, result_{ &result } - {} + { + set_indent_string(indent); + } #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 void formatter::attach(std::ostream & stream) noexcept { @@ -62,7 +73,7 @@ TOML_IMPL_NAMESPACE_START { for (int i = 0; i < indent_; i++) { - print_to_stream(*stream_, indent_string); + print_to_stream(*stream_, indent_string_); naked_newline_ = false; } } @@ -216,7 +227,7 @@ TOML_IMPL_NAMESPACE_START #if TOML_PARSER && !TOML_EXCEPTIONS TOML_EXTERNAL_LINKAGE - bool formatter::dump_failed_parse_result() noexcept(false) + bool formatter::dump_failed_parse_result() { if (result_ && !(*result_)) { @@ -230,7 +241,7 @@ TOML_IMPL_NAMESPACE_START TOML_EXTERNAL_LINKAGE TOML_ATTR(const) - bool formatter::dump_failed_parse_result() noexcept(true) + bool formatter::dump_failed_parse_result() { return false; } diff --git a/include/toml++/impl/forward_declarations.h b/include/toml++/impl/forward_declarations.h index 319eade..08f2a5d 100644 --- a/include/toml++/impl/forward_declarations.h +++ b/include/toml++/impl/forward_declarations.h @@ -333,10 +333,14 @@ TOML_NAMESPACE_START // abi namespace template struct TOML_TRIVIAL_ABI inserter { - T&& value; + static_assert(std::is_reference_v); + + T value; }; template - inserter(T &&) -> inserter; + inserter(T &&) -> inserter; + template + inserter(T&) -> inserter; } TOML_NAMESPACE_END; diff --git a/include/toml++/impl/json_formatter.h b/include/toml++/impl/json_formatter.h index aedf8ba..4b5f76b 100644 --- a/include/toml++/impl/json_formatter.h +++ b/include/toml++/impl/json_formatter.h @@ -72,7 +72,7 @@ TOML_NAMESPACE_START /// \param flags Format option flags. TOML_NODISCARD_CTOR explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept - : base{ source, (flags | mandatory_flags) & ~ignored_flags } + : base{ source, (flags | mandatory_flags) & ~ignored_flags, " "sv } {} #if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS) @@ -103,7 +103,7 @@ TOML_NAMESPACE_START /// \param flags Format option flags. TOML_NODISCARD_CTOR explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept - : base{ result, (flags | mandatory_flags) & ~ignored_flags } + : base{ result, (flags | mandatory_flags) & ~ignored_flags, " "sv } {} #endif diff --git a/include/toml++/impl/make_node.h b/include/toml++/impl/make_node.h index 5727743..55a4674 100644 --- a/include/toml++/impl/make_node.h +++ b/include/toml++/impl/make_node.h @@ -13,45 +13,67 @@ TOML_IMPL_NAMESPACE_START template TOML_NODISCARD 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>; - static_assert(!std::is_same_v); - static_assert(!is_node_view); + using unwrapped_type = unwrap_node>; + static_assert(!std::is_same_v); + static_assert(!is_node_view); - if constexpr (is_one_of) + // arrays + tables - invoke copy/move ctor + if constexpr (is_one_of) { - return new type{ static_cast(val) }; - } - else if constexpr (is_native && !std::is_same_v, type>) - { - return new value{ static_cast(val) }; + return new unwrapped_type{ static_cast(val) }; } + + // values else { - static_assert(!is_wide_string || TOML_WINDOWS_COMPAT, - "Instantiating values from wide-character strings is only " - "supported on Windows with TOML_WINDOWS_COMPAT enabled."); - static_assert(is_native || is_losslessly_convertible_to_native, - "Value initializers must be (or be promotable to) one of the TOML value types"); + using native_type = native_type_of; + using value_type = value; - using value_type = native_type_of>; - if constexpr (is_wide_string) + value_type* out; + + // copy/move ctor + if constexpr (std::is_same_v, value_type>) { -#if TOML_WINDOWS_COMPAT - return new value{ narrow(static_cast(val)) }; -#else - static_assert(dependent_false, "Evaluated unreachable branch!"); -#endif + out = new value_type{ static_cast(val) }; + + // only override the flags if the new ones are nonzero + // (so the copy/move ctor does the right thing in the general case) + if (flags != value_flags::none) + out->flags(flags); } + + // creating from raw value else - return new value{ static_cast(val) }; + { + static_assert(!is_wide_string || TOML_WINDOWS_COMPAT, + "Instantiating values from wide-character strings is only " + "supported on Windows with TOML_WINDOWS_COMPAT enabled."); + static_assert(is_native || is_losslessly_convertible_to_native, + "Value initializers must be (or be promotable to) one of the TOML value types"); + + if constexpr (is_wide_string) + { +#if TOML_WINDOWS_COMPAT + out = new value_type{ narrow(static_cast(val)) }; +#else + static_assert(dependent_false, "Evaluated unreachable branch!"); +#endif + } + else + out = new value_type{ static_cast(val) }; + + out->flags(flags); + } + + return out; } } template TOML_NODISCARD - auto* make_node(T && val) + auto* make_node(T && val, value_flags flags = value_flags::none) { using type = unwrap_node>; if constexpr (std::is_same_v || is_node_view) @@ -63,19 +85,20 @@ TOML_IMPL_NAMESPACE_START } return static_cast(val).visit( - [](auto&& concrete) { - return static_cast(make_node_specialized(static_cast(concrete))); + [flags](auto&& concrete) { + return static_cast( + make_node_specialized(static_cast(concrete), flags)); }); } else - return make_node_specialized(static_cast(val)); + return make_node_specialized(static_cast(val), flags); } template TOML_NODISCARD - auto* make_node(inserter && val) + auto* make_node(inserter && val, value_flags flags = value_flags::none) { - return make_node(static_cast(val.value)); + return make_node(static_cast(val.value), flags); } template || is_node_view || is_value || can_partially_represent_native)> diff --git a/include/toml++/impl/node_view.h b/include/toml++/impl/node_view.h index 636397e..ab79ef6 100644 --- a/include/toml++/impl/node_view.h +++ b/include/toml++/impl/node_view.h @@ -2,8 +2,8 @@ //# Copyright (c) Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT - #pragma once + #include "print_to_stream.h" #include "node.h" #include "std_vector.h" @@ -746,7 +746,7 @@ TOML_NAMESPACE_START TOML_NAMESPACE_END; /// \cond -#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION #include "node_view_extern.inl" #endif diff --git a/include/toml++/impl/node_view.inl b/include/toml++/impl/node_view.inl index 07ea5d0..6e137c7 100644 --- a/include/toml++/impl/node_view.inl +++ b/include/toml++/impl/node_view.inl @@ -14,7 +14,7 @@ #include "node_view.h" #include "header_start.h" -#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION #include "node_view_extern.inl" #endif // TOML_EXTERN_TEMPLATES diff --git a/include/toml++/impl/node_view_extern.inl b/include/toml++/impl/node_view_extern.inl index 96fa752..74e9ac9 100644 --- a/include/toml++/impl/node_view_extern.inl +++ b/include/toml++/impl/node_view_extern.inl @@ -2,7 +2,6 @@ //# Copyright (c) Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT -#pragma once /// \cond #include "node_view.h" diff --git a/include/toml++/impl/table.h b/include/toml++/impl/table.h index 3fb7aa7..0143da0 100644 --- a/include/toml++/impl/table.h +++ b/include/toml++/impl/table.h @@ -159,46 +159,46 @@ TOML_IMPL_NAMESPACE_START template 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) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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 }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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 }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} #if TOML_WINDOWS_COMPAT template 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) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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 }) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} #endif @@ -650,6 +650,10 @@ TOML_NAMESPACE_START /// (or a type promotable to one). /// \param key The key at which to insert the new value. /// \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} ///
    @@ -665,7 +669,7 @@ TOML_NAMESPACE_START TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v || impl::is_wide_string), typename KeyType, typename ValueType) - std::pair insert(KeyType&& key, ValueType&& val) + std::pair insert(KeyType&& key, ValueType&& val, value_flags flags = value_flags::none) { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, @@ -680,7 +684,7 @@ TOML_NAMESPACE_START if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT - return insert(impl::narrow(std::forward(key)), std::forward(val)); + return insert(impl::narrow(std::forward(key)), std::forward(val), flags); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif @@ -692,7 +696,7 @@ TOML_NAMESPACE_START { ipos = map_.emplace_hint(ipos, std::forward(key), - impl::make_node(std::forward(val))); + impl::make_node(std::forward(val), flags)); return { iterator{ ipos }, true }; } return { iterator{ ipos }, false }; @@ -734,22 +738,26 @@ TOML_NAMESPACE_START /// \tparam Iter An InputIterator to a collection of key-value pairs. /// \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 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 /// 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 && !impl::is_wide_string), typename Iter) - void insert(Iter first, Iter last) + void insert(Iter first, Iter last, value_flags flags = value_flags::none) { if (first == last) return; for (auto it = first; it != last; it++) { if constexpr (std::is_rvalue_reference_v) - insert(std::move((*it).first), std::move((*it).second)); + insert(std::move((*it).first), std::move((*it).second), flags); 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). /// \param key The key at which to insert or assign the value. /// \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} ///
      @@ -806,7 +818,9 @@ TOML_NAMESPACE_START /// an empty toml::node_view, because no insertion or assignment can take place. /// This is the only circumstance in which this can occur. template - std::pair insert_or_assign(KeyType&& key, ValueType&& val) + std::pair insert_or_assign(KeyType&& key, + ValueType&& val, + value_flags flags = value_flags::none) { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, @@ -821,7 +835,7 @@ TOML_NAMESPACE_START if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT - return insert_or_assign(impl::narrow(std::forward(key)), std::forward(val)); + return insert_or_assign(impl::narrow(std::forward(key)), std::forward(val), flags); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif @@ -833,12 +847,12 @@ TOML_NAMESPACE_START { ipos = map_.emplace_hint(ipos, std::forward(key), - impl::make_node(std::forward(val))); + impl::make_node(std::forward(val), flags)); return { iterator{ ipos }, true }; } else { - (*ipos).second.reset(impl::make_node(std::forward(val))); + (*ipos).second.reset(impl::make_node(std::forward(val), flags)); return { iterator{ ipos }, false }; } } diff --git a/include/toml++/impl/utf8.h b/include/toml++/impl/utf8.h index ac9f197..e394e09 100644 --- a/include/toml++/impl/utf8.h +++ b/include/toml++/impl/utf8.h @@ -10,15 +10,13 @@ /// \cond TOML_IMPL_NAMESPACE_START { - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept { return codepoint == U'\t' || codepoint == U' '; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept { // see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode @@ -33,24 +31,21 @@ TOML_IMPL_NAMESPACE_START ; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_whitespace(char32_t codepoint) noexcept { return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint); } template - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_ascii_line_break(char32_t codepoint) noexcept { constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f'; return (codepoint >= U'\n' && codepoint <= low_range_end); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept { // see https://en.wikipedia.org/wiki/Whitespace_character#Unicode @@ -63,58 +58,50 @@ TOML_IMPL_NAMESPACE_START } template - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_line_break(char32_t codepoint) noexcept { return is_ascii_line_break(codepoint) || is_non_ascii_line_break(codepoint); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_string_delimiter(char32_t codepoint) noexcept { return codepoint == U'"' || codepoint == U'\''; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_ascii_letter(char32_t codepoint) noexcept { return (codepoint >= U'a' && codepoint <= U'z') || (codepoint >= U'A' && codepoint <= U'Z'); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_binary_digit(char32_t codepoint) noexcept { return codepoint == U'0' || codepoint == U'1'; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_octal_digit(char32_t codepoint) noexcept { return (codepoint >= U'0' && codepoint <= U'7'); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_decimal_digit(char32_t codepoint) noexcept { return (codepoint >= U'0' && codepoint <= U'9'); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_hexadecimal_digit(char32_t c) noexcept { return U'0' <= c && c <= U'f' && (1ull << (static_cast(c) - 0x30u)) & 0x7E0000007E03FFull; } template - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr uint_least32_t hex_to_dec(const T codepoint) noexcept { if constexpr (std::is_same_v, uint_least32_t>) @@ -130,8 +117,7 @@ TOML_IMPL_NAMESPACE_START //# Returns true if a codepoint belongs to any of these categories: //# Ll, Lm, Lo, Lt, Lu - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_letter(char32_t c) noexcept { 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: //# Nd, Nl - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_number(char32_t c) noexcept { 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: //# Mn, Mc - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_combining_mark(char32_t c) noexcept { if (U'\u0300' > c || c > U'\U000E01EF') @@ -849,8 +833,7 @@ TOML_IMPL_NAMESPACE_START #endif // TOML_LANG_UNRELEASED - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_bare_key_character(char32_t codepoint) noexcept { return is_ascii_letter(codepoint) || is_decimal_digit(codepoint) || codepoint == U'-' || codepoint == U'_' @@ -861,8 +844,7 @@ TOML_IMPL_NAMESPACE_START ; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_value_terminator(char32_t codepoint) noexcept { 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); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_control_character(char32_t codepoint) noexcept { return codepoint <= U'\u001F' || codepoint == U'\u007F'; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_nontab_control_character(char32_t codepoint) noexcept { return codepoint <= U'\u0008' || (codepoint >= U'\u000A' && codepoint <= U'\u001F') || codepoint == U'\u007F'; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept { 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 }; - TOML_NODISCARD + TOML_PURE_INLINE_GETTER constexpr bool error() const noexcept { return state == uint_least32_t{ 12u }; } - TOML_NODISCARD + TOML_PURE_INLINE_GETTER constexpr bool has_code_point() const noexcept { return state == uint_least32_t{}; @@ -947,6 +926,12 @@ TOML_IMPL_NAMESPACE_START state = state_table[state + uint_least32_t{ 256u } + type]; } + + TOML_ALWAYS_INLINE + constexpr void reset() noexcept + { + state = {}; + } }; } TOML_IMPL_NAMESPACE_END; diff --git a/include/toml++/impl/value.h b/include/toml++/impl/value.h index cc7df9a..7819050 100644 --- a/include/toml++/impl/value.h +++ b/include/toml++/impl/value.h @@ -2,8 +2,8 @@ //# Copyright (c) Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT - #pragma once + #include "date_time.h" #include "node.h" #include "print_to_stream.h" @@ -1105,7 +1105,7 @@ TOML_NAMESPACE_START TOML_NAMESPACE_END; /// \cond -#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION #include "value_extern.inl" #endif /// \endcond diff --git a/include/toml++/impl/value.inl b/include/toml++/impl/value.inl index a82c4e7..d96fdca 100644 --- a/include/toml++/impl/value.inl +++ b/include/toml++/impl/value.inl @@ -14,7 +14,7 @@ #include "value.h" #include "header_start.h" -#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION #include "value_extern.inl" #endif // TOML_EXTERN_TEMPLATES diff --git a/include/toml++/impl/value_extern.inl b/include/toml++/impl/value_extern.inl index 4091a59..f30215b 100644 --- a/include/toml++/impl/value_extern.inl +++ b/include/toml++/impl/value_extern.inl @@ -2,7 +2,6 @@ //# Copyright (c) Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT -#pragma once /// \cond #include "value.h" diff --git a/toml.hpp b/toml.hpp index f3d5ddd..1a2f2b6 100644 --- a/toml.hpp +++ b/toml.hpp @@ -1197,10 +1197,14 @@ TOML_NAMESPACE_START // abi namespace template struct TOML_TRIVIAL_ABI inserter { - T&& value; + static_assert(std::is_reference_v); + + T value; }; template - inserter(T &&) -> inserter; + inserter(T &&) -> inserter; + template + inserter(T&) -> inserter; } TOML_NAMESPACE_END; @@ -3302,7 +3306,7 @@ TOML_NAMESPACE_START } TOML_NAMESPACE_END; -#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION TOML_NAMESPACE_START { @@ -4344,7 +4348,7 @@ TOML_NAMESPACE_START } TOML_NAMESPACE_END; -#if (TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION TOML_NAMESPACE_START { @@ -4428,45 +4432,67 @@ TOML_IMPL_NAMESPACE_START template TOML_NODISCARD 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>; - static_assert(!std::is_same_v); - static_assert(!is_node_view); + using unwrapped_type = unwrap_node>; + static_assert(!std::is_same_v); + static_assert(!is_node_view); - if constexpr (is_one_of) + // arrays + tables - invoke copy/move ctor + if constexpr (is_one_of) { - return new type{ static_cast(val) }; - } - else if constexpr (is_native && !std::is_same_v, type>) - { - return new value{ static_cast(val) }; + return new unwrapped_type{ static_cast(val) }; } + + // values else { - static_assert(!is_wide_string || TOML_WINDOWS_COMPAT, - "Instantiating values from wide-character strings is only " - "supported on Windows with TOML_WINDOWS_COMPAT enabled."); - static_assert(is_native || is_losslessly_convertible_to_native, - "Value initializers must be (or be promotable to) one of the TOML value types"); + using native_type = native_type_of; + using value_type = value; - using value_type = native_type_of>; - if constexpr (is_wide_string) + value_type* out; + + // copy/move ctor + if constexpr (std::is_same_v, value_type>) { -#if TOML_WINDOWS_COMPAT - return new value{ narrow(static_cast(val)) }; -#else - static_assert(dependent_false, "Evaluated unreachable branch!"); -#endif + out = new value_type{ static_cast(val) }; + + // only override the flags if the new ones are nonzero + // (so the copy/move ctor does the right thing in the general case) + if (flags != value_flags::none) + out->flags(flags); } + + // creating from raw value else - return new value{ static_cast(val) }; + { + static_assert(!is_wide_string || TOML_WINDOWS_COMPAT, + "Instantiating values from wide-character strings is only " + "supported on Windows with TOML_WINDOWS_COMPAT enabled."); + static_assert(is_native || is_losslessly_convertible_to_native, + "Value initializers must be (or be promotable to) one of the TOML value types"); + + if constexpr (is_wide_string) + { +#if TOML_WINDOWS_COMPAT + out = new value_type{ narrow(static_cast(val)) }; +#else + static_assert(dependent_false, "Evaluated unreachable branch!"); +#endif + } + else + out = new value_type{ static_cast(val) }; + + out->flags(flags); + } + + return out; } } template TOML_NODISCARD - auto* make_node(T && val) + auto* make_node(T && val, value_flags flags = value_flags::none) { using type = unwrap_node>; if constexpr (std::is_same_v || is_node_view) @@ -4478,19 +4504,20 @@ TOML_IMPL_NAMESPACE_START } return static_cast(val).visit( - [](auto&& concrete) { - return static_cast(make_node_specialized(static_cast(concrete))); + [flags](auto&& concrete) { + return static_cast( + make_node_specialized(static_cast(concrete), flags)); }); } else - return make_node_specialized(static_cast(val)); + return make_node_specialized(static_cast(val), flags); } template TOML_NODISCARD - auto* make_node(inserter && val) + auto* make_node(inserter && val, value_flags flags = value_flags::none) { - return make_node(static_cast(val.value)); + return make_node(static_cast(val.value), flags); } template || is_node_view || is_value || can_partially_represent_native)> @@ -4717,14 +4744,14 @@ TOML_NAMESPACE_START void preinsertion_resize(size_t idx, size_t count); template - 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) { if (!val) return; } - elements.emplace_back(impl::make_node(static_cast(val))); + elements.emplace_back(impl::make_node(static_cast(val), flags)); } TOML_NODISCARD @@ -4786,10 +4813,10 @@ TOML_NAMESPACE_START explicit array(ElemType&& val, ElemTypes&&... vals) { elements.reserve(sizeof...(ElemTypes) + 1u); - emplace_back_if_not_empty_view(static_cast(val)); + emplace_back_if_not_empty_view(static_cast(val), value_flags::none); if constexpr (sizeof...(ElemTypes) > 0) { - (emplace_back_if_not_empty_view(static_cast(vals)), ...); + (emplace_back_if_not_empty_view(static_cast(vals), value_flags::none), ...); } #if TOML_LIFETIME_HOOKS @@ -4964,18 +4991,18 @@ TOML_NAMESPACE_START } template - 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) { if (!val) return end(); } - return { elements.emplace(pos.raw_, impl::make_node(static_cast(val))) }; + return { elements.emplace(pos.raw_, impl::make_node(static_cast(val), flags)) }; } template - 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) { @@ -4985,23 +5012,23 @@ TOML_NAMESPACE_START switch (count) { case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; - case 1: return insert(pos, static_cast(val)); + case 1: return insert(pos, static_cast(val), flags); default: { const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); preinsertion_resize(start_idx, count); size_t i = start_idx; 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(val))); + elements[i].reset(impl::make_node(static_cast(val), flags)); return { elements.begin() + static_cast(start_idx) }; } } } template - 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); if (distance <= 0) @@ -5029,18 +5056,20 @@ TOML_NAMESPACE_START continue; } if constexpr (std::is_rvalue_reference_v) - elements[i++].reset(impl::make_node(std::move(*it))); + elements[i++].reset(impl::make_node(std::move(*it), flags)); else - elements[i++].reset(impl::make_node(*it)); + elements[i++].reset(impl::make_node(*it, flags)); } return { elements.begin() + static_cast(start_idx) }; } } template - iterator insert(const_iterator pos, std::initializer_list ilist) + iterator insert(const_iterator pos, + std::initializer_list ilist, + value_flags flags = value_flags::none) { - return insert(pos, ilist.begin(), ilist.end()); + return insert(pos, ilist.begin(), ilist.end(), flags); } template @@ -5084,9 +5113,9 @@ TOML_NAMESPACE_START } template - void push_back(ElemType&& val) + void push_back(ElemType&& val, value_flags flags = value_flags::none) { - emplace_back_if_not_empty_view(static_cast(val)); + emplace_back_if_not_empty_view(static_cast(val), flags); } template @@ -5374,46 +5403,46 @@ TOML_IMPL_NAMESPACE_START template 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) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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 }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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 }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} #if TOML_WINDOWS_COMPAT template 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) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} template 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 }) }, - value{ make_node(static_cast(v)) } + value{ make_node(static_cast(v), flags) } {} #endif @@ -5671,7 +5700,7 @@ TOML_NAMESPACE_START TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v || impl::is_wide_string), typename KeyType, typename ValueType) - std::pair insert(KeyType&& key, ValueType&& val) + std::pair insert(KeyType&& key, ValueType&& val, value_flags flags = value_flags::none) { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, @@ -5686,7 +5715,7 @@ TOML_NAMESPACE_START if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT - return insert(impl::narrow(std::forward(key)), std::forward(val)); + return insert(impl::narrow(std::forward(key)), std::forward(val), flags); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif @@ -5698,7 +5727,7 @@ TOML_NAMESPACE_START { ipos = map_.emplace_hint(ipos, std::forward(key), - impl::make_node(std::forward(val))); + impl::make_node(std::forward(val), flags)); return { iterator{ ipos }, true }; } return { iterator{ ipos }, false }; @@ -5707,21 +5736,23 @@ TOML_NAMESPACE_START TOML_CONSTRAINED_TEMPLATE((!std::is_convertible_v && !impl::is_wide_string), typename Iter) - void insert(Iter first, Iter last) + void insert(Iter first, Iter last, value_flags flags = value_flags::none) { if (first == last) return; for (auto it = first; it != last; it++) { if constexpr (std::is_rvalue_reference_v) - insert(std::move((*it).first), std::move((*it).second)); + insert(std::move((*it).first), std::move((*it).second), flags); else - insert((*it).first, (*it).second); + insert((*it).first, (*it).second, flags); } } template - std::pair insert_or_assign(KeyType&& key, ValueType&& val) + std::pair insert_or_assign(KeyType&& key, + ValueType&& val, + value_flags flags = value_flags::none) { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, @@ -5736,7 +5767,7 @@ TOML_NAMESPACE_START if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT - return insert_or_assign(impl::narrow(std::forward(key)), std::forward(val)); + return insert_or_assign(impl::narrow(std::forward(key)), std::forward(val), flags); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif @@ -5748,12 +5779,12 @@ TOML_NAMESPACE_START { ipos = map_.emplace_hint(ipos, std::forward(key), - impl::make_node(std::forward(val))); + impl::make_node(std::forward(val), flags)); return { iterator{ ipos }, true }; } else { - (*ipos).second.reset(impl::make_node(std::forward(val))); + (*ipos).second.reset(impl::make_node(std::forward(val), flags)); return { iterator{ ipos }, false }; } } @@ -5966,15 +5997,13 @@ TOML_DISABLE_SWITCH_WARNINGS; TOML_IMPL_NAMESPACE_START { - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept { return codepoint == U'\t' || codepoint == U' '; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept { // see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode @@ -5989,24 +6018,21 @@ TOML_IMPL_NAMESPACE_START ; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_whitespace(char32_t codepoint) noexcept { return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint); } template - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_ascii_line_break(char32_t codepoint) noexcept { constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f'; return (codepoint >= U'\n' && codepoint <= low_range_end); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept { // see https://en.wikipedia.org/wiki/Whitespace_character#Unicode @@ -6019,58 +6045,50 @@ TOML_IMPL_NAMESPACE_START } template - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_line_break(char32_t codepoint) noexcept { return is_ascii_line_break(codepoint) || is_non_ascii_line_break(codepoint); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_string_delimiter(char32_t codepoint) noexcept { return codepoint == U'"' || codepoint == U'\''; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_ascii_letter(char32_t codepoint) noexcept { return (codepoint >= U'a' && codepoint <= U'z') || (codepoint >= U'A' && codepoint <= U'Z'); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_binary_digit(char32_t codepoint) noexcept { return codepoint == U'0' || codepoint == U'1'; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_octal_digit(char32_t codepoint) noexcept { return (codepoint >= U'0' && codepoint <= U'7'); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_decimal_digit(char32_t codepoint) noexcept { return (codepoint >= U'0' && codepoint <= U'9'); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_hexadecimal_digit(char32_t c) noexcept { return U'0' <= c && c <= U'f' && (1ull << (static_cast(c) - 0x30u)) & 0x7E0000007E03FFull; } template - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr uint_least32_t hex_to_dec(const T codepoint) noexcept { if constexpr (std::is_same_v, uint_least32_t>) @@ -6084,8 +6102,7 @@ TOML_IMPL_NAMESPACE_START #if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys) - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_letter(char32_t c) noexcept { if (U'\xAA' > c || c > U'\U0003134A') @@ -6436,8 +6453,7 @@ TOML_IMPL_NAMESPACE_START TOML_UNREACHABLE; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_non_ascii_number(char32_t c) noexcept { if (U'\u0660' > c || c > U'\U0001FBF9') @@ -6588,8 +6604,7 @@ TOML_IMPL_NAMESPACE_START TOML_UNREACHABLE; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_combining_mark(char32_t c) noexcept { if (U'\u0300' > c || c > U'\U000E01EF') @@ -6799,8 +6814,7 @@ TOML_IMPL_NAMESPACE_START #endif // TOML_LANG_UNRELEASED - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_bare_key_character(char32_t codepoint) noexcept { return is_ascii_letter(codepoint) || is_decimal_digit(codepoint) || codepoint == U'-' || codepoint == U'_' @@ -6811,8 +6825,7 @@ TOML_IMPL_NAMESPACE_START ; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_value_terminator(char32_t codepoint) noexcept { 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); } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_control_character(char32_t codepoint) noexcept { return codepoint <= U'\u001F' || codepoint == U'\u007F'; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_nontab_control_character(char32_t codepoint) noexcept { return codepoint <= U'\u0008' || (codepoint >= U'\u000A' && codepoint <= U'\u001F') || codepoint == U'\u007F'; } - TOML_NODISCARD - TOML_ATTR(const) + TOML_CONST_GETTER constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept { 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 }; - TOML_NODISCARD + TOML_PURE_INLINE_GETTER constexpr bool error() const noexcept { return state == uint_least32_t{ 12u }; } - TOML_NODISCARD + TOML_PURE_INLINE_GETTER constexpr bool has_code_point() const noexcept { return state == uint_least32_t{}; @@ -6896,6 +6906,12 @@ TOML_IMPL_NAMESPACE_START state = state_table[state + uint_least32_t{ 256u } + type]; } + + TOML_ALWAYS_INLINE + constexpr void reset() noexcept + { + state = {}; + } }; } TOML_IMPL_NAMESPACE_END; @@ -7412,14 +7428,16 @@ TOML_IMPL_NAMESPACE_START format_flags flags_; // int indent_; // these are set in attach() bool naked_newline_; // + std::string_view indent_string_; + size_t indent_columns_; #if TOML_PARSER && !TOML_EXCEPTIONS const parse_result* result_ = {}; #endif - protected: - static constexpr size_t indent_columns = 4; - static constexpr std::string_view indent_string = " "sv; + TOML_API + void set_indent_string(std::string_view str) noexcept; + protected: TOML_PURE_INLINE_GETTER const toml::node& source() const noexcept { @@ -7453,6 +7471,12 @@ TOML_IMPL_NAMESPACE_START indent_--; } + TOML_PURE_INLINE_GETTER + size_t indent_columns() const noexcept + { + return indent_columns_; + } + TOML_PURE_INLINE_GETTER bool indent_array_elements() const noexcept { @@ -7541,19 +7565,21 @@ TOML_IMPL_NAMESPACE_START TOML_NODISCARD TOML_API - bool dump_failed_parse_result() noexcept(!TOML_PARSER || TOML_EXCEPTIONS); + bool dump_failed_parse_result(); 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 }, flags_{ flags } - {} + { + set_indent_string(indent); + } #if TOML_PARSER && !TOML_EXCEPTIONS TOML_NODISCARD_CTOR 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 }; @@ -7625,14 +7651,14 @@ TOML_NAMESPACE_START TOML_NODISCARD_CTOR 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) TOML_NODISCARD_CTOR 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 @@ -7690,14 +7716,14 @@ TOML_NAMESPACE_START TOML_NODISCARD_CTOR 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) TOML_NODISCARD_CTOR 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 @@ -8316,7 +8342,7 @@ TOML_PUSH_WARNINGS; TOML_DISABLE_SPAM_WARNINGS; TOML_DISABLE_SWITCH_WARNINGS; -#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION TOML_NAMESPACE_START { @@ -8390,7 +8416,7 @@ TOML_PUSH_WARNINGS; TOML_DISABLE_SPAM_WARNINGS; TOML_DISABLE_SWITCH_WARNINGS; -#if (TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION) || TOML_INTELLISENSE +#if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION TOML_NAMESPACE_START { @@ -12498,14 +12524,25 @@ TOML_IMPL_NAMESPACE_START #if TOML_PARSER && !TOML_EXCEPTIONS 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 }, flags_{ flags }, result_{ &result } - {} + { + set_indent_string(indent); + } #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 void formatter::attach(std::ostream & stream) noexcept { @@ -12535,7 +12572,7 @@ TOML_IMPL_NAMESPACE_START { for (int i = 0; i < indent_; i++) { - print_to_stream(*stream_, indent_string); + print_to_stream(*stream_, indent_string_); naked_newline_ = false; } } @@ -12689,7 +12726,7 @@ TOML_IMPL_NAMESPACE_START #if TOML_PARSER && !TOML_EXCEPTIONS TOML_EXTERNAL_LINKAGE - bool formatter::dump_failed_parse_result() noexcept(false) + bool formatter::dump_failed_parse_result() { if (result_ && !(*result_)) { @@ -12703,7 +12740,7 @@ TOML_IMPL_NAMESPACE_START TOML_EXTERNAL_LINKAGE TOML_ATTR(const) - bool formatter::dump_failed_parse_result() noexcept(true) + bool formatter::dump_failed_parse_result() { return false; } @@ -12774,11 +12811,11 @@ TOML_NAMESPACE_START { case node_type::table: { - auto& n = *reinterpret_cast(&node); - if (n.empty()) + auto& tbl = *reinterpret_cast(&node); + if (tbl.empty()) return 2u; // "{}" size_t weight = 3u; // "{ }" - for (auto&& [k, v] : n) + for (auto&& [k, v] : tbl) { weight += k.length() + count_inline_columns(v) + 2u; // + ", " if (weight >= line_wrap_cols) @@ -12789,11 +12826,11 @@ TOML_NAMESPACE_START case node_type::array: { - auto& n = *reinterpret_cast(&node); - if (n.empty()) + auto& arr = *reinterpret_cast(&node); + if (arr.empty()) return 2u; // "[]" size_t weight = 3u; // "[ ]" - for (auto& elem : n) + for (auto& elem : arr) { weight += count_inline_columns(elem) + 2u; // + ", " if (weight >= line_wrap_cols) @@ -12804,38 +12841,38 @@ TOML_NAMESPACE_START case node_type::string: { - auto& n = *reinterpret_cast*>(&node); - return n.get().length() + 2u; // + "" + // todo: proper utf8 decoding? + // todo: tab awareness? + auto& str = (*reinterpret_cast*>(&node)).get(); + return str.length() + 2u; // + "" } case node_type::integer: { - auto& n = *reinterpret_cast*>(&node); - auto v = n.get(); - if (!v) + auto val = (*reinterpret_cast*>(&node)).get(); + if (!val) return 1u; size_t weight = {}; - if (v < 0) + if (val < 0) { weight += 1u; - v *= -1; + val *= -1; } - return weight + static_cast(log10(static_cast(v))) + 1u; + return weight + static_cast(log10(static_cast(val))) + 1u; } case node_type::floating_point: { - auto& n = *reinterpret_cast*>(&node); - auto v = n.get(); - if (v == 0.0) + auto val = (*reinterpret_cast*>(&node)).get(); + if (val == 0.0) return 3u; // "0.0" size_t weight = 2u; // ".0" - if (v < 0.0) + if (val < 0.0) { weight += 1u; - v *= -1.0; + val *= -1.0; } - return weight + static_cast(log10(v)) + 1u; + return weight + static_cast(log10(val)) + 1u; break; } @@ -12953,9 +12990,9 @@ TOML_NAMESPACE_START else { const auto original_indent = base::indent(); - const auto multiline = - forces_multiline(arr, - base::indent_columns * static_cast(original_indent < 0 ? 0 : original_indent)); + const auto multiline = forces_multiline( + arr, + base::indent_columns() * static_cast(original_indent < 0 ? 0 : original_indent)); impl::print_to_stream(base::stream(), "["sv); if (multiline) { diff --git a/tools/generate_single_header.py b/tools/generate_single_header.py index 21e0b1f..d5620e1 100644 --- a/tools/generate_single_header.py +++ b/tools/generate_single_header.py @@ -16,15 +16,10 @@ from io import StringIO class Preprocessor: __re_includes = re.compile(r'^\s*#\s*include\s+"(.+?)".*?$', re.I | re.M) - __multiples_allowed = [ - r'impl/header_start.h', - r'impl/header_end.h', - r'impl/value_extern.inl', - r'impl/node_view_extern.inl', - ] + __re_pragma_once = re.compile(r'^\s*#\s*pragma\s+once\s*$', re.M) def __init__(self, file): - self.__processed_includes = set() + self.__once_only = set() self.__current_level = 0 self.__directory_stack = [ Path.cwd() ] self.__entry_root = '' @@ -38,27 +33,30 @@ class Preprocessor: incl = Path(incl.strip().replace('\\',r'/')) if not incl.is_absolute(): incl = Path(self.__directory_stack[-1], incl).resolve() - if self.__current_level == 0 and self.__entry_root == '': - 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: + if incl in self.__once_only: 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 = 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 text = self.__re_includes.sub(lambda m : self.__preprocess(m), text, 0) 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}' self.__directory_stack.pop() @@ -80,8 +78,6 @@ def main(): # strip various things: if 1: - # 'pragma once' - toml_h = re.sub(r'^\s*#\s*pragma\s+once\s*$', '', toml_h, 0, re.I | re.M) # trailing whitespace toml_h = re.sub('([^ \t])[ \t]+\n', r'\1\n', toml_h) # explicit 'strip this' blocks