added additional metafunctions

also:
- reduced bloat by removing unnecessary std::forwards and std::moves
- minor cleanup of example code
This commit is contained in:
Mark Gillard 2021-05-21 14:28:45 +03:00
parent 7bf8c03f7a
commit 6135deb6a3
21 changed files with 557 additions and 407 deletions

View File

@ -2,26 +2,21 @@
// 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
/*
This example is one of diagnostics; it forces a set of specific parsing // This example shows the error messages the library produces by forcing a set of specific parsing
failures and prints their error messages to stdout so you can see what the // failures and printing their results.
default error messages look like.
*/ #include "examples.h"
#include <iostream>
#include "utf8_console.h"
#define TOML_EXCEPTIONS 0 #define TOML_EXCEPTIONS 0
#define TOML_UNRELEASED_FEATURES 0 #define TOML_UNRELEASED_FEATURES 0
#include <toml++/toml.h> #include <toml++/toml.h>
using namespace std::string_view_literals; using namespace std::string_view_literals;
using toml::operator""_sz;
namespace namespace
{ {
inline constexpr std::string_view invalid_parses[] = inline constexpr auto invalid_parses = std::array
{ {
"########## comments"sv, "########## comments"sv,
"# bar\rkek"sv, "# bar\rkek"sv,
@ -104,44 +99,36 @@ namespace
"########## floats"sv, "########## floats"sv,
R"(val = 9999999999999999999999999999999999999999999999999999999999999995.0)"sv, R"(val = 9999999999999999999999999999999999999999999999999999999999999995.0)"sv,
}; };
inline constexpr auto divider =
"################################################################################"sv;
} }
int main()
int main(int /*argc*/, char** /*argv*/)
{ {
std::ios_base::sync_with_stdio(false); examples::init();
init_utf8_console();
for (auto str : invalid_parses) for (auto str : invalid_parses)
{ {
if (str.empty()) if (str.empty())
continue; continue;
if (str.substr(0_sz, 10_sz) == "##########"sv) // section headings
if (str.substr(0, 10) == "##########"sv)
{ {
const auto substr = str.substr(11_sz); std::cout << divider << '\n';
size_t cols = 80_sz; std::cout << "# "sv << str.substr(11) << '\n';
for (size_t i = (cols - substr.length()) / 2_sz - 1_sz; i-- > 0_sz; ) std::cout << divider << "\n\n"sv;
{
std::cout.put('#');
cols--;
}
std::cout.put(' ');
std::cout << substr;
std::cout.put(' ');
cols -= substr.length() + 2_sz;
while (cols--)
std::cout.put('#');
std::cout << "\n\n"sv;
} }
// error messages
else else
{ {
toml::parse_result result; toml::parse_result result;
if (str == "PATHOLOGICALLY_NESTED"sv) if (str == "PATHOLOGICALLY_NESTED"sv)
{ {
std::string s(1000_sz, '['); std::string s(1000u, '[');
constexpr auto start = "array = "sv; constexpr auto start = "array = "sv;
memcpy(s.data(), start.data(), start.length()); memcpy(s.data(), start.data(), start.length());
result = toml::parse(s); result = toml::parse(s);
@ -150,10 +137,7 @@ int main(int /*argc*/, char** /*argv*/)
result = toml::parse(str); result = toml::parse(str);
if (!result) if (!result)
{ std::cout << result.error() << "\n\n"sv;
std::cout << result.error();
std::cout << "\n\n"sv;
}
} }
} }
return 0; return 0;

View File

@ -51,5 +51,11 @@
<ItemGroup> <ItemGroup>
<None Include="meson.build" /> <None Include="meson.build" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project> </Project>

52
examples/examples.h Normal file
View File

@ -0,0 +1,52 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
// this file is for boilerplate unrelated to the toml++ example learning outcomes.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#elif defined (__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#elif defined(_MSC_VER)
#pragma warning(push, 0)
#endif
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include <array>
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif
namespace examples
{
inline void init() noexcept
{
#ifdef _WIN32
SetConsoleOutputCP(65001); //CP_UTF8
#endif
std::ios_base::sync_with_stdio(false);
std::cout << std::boolalpha;
srand(static_cast<unsigned int>(time(nullptr)));
}
}

View File

@ -2,14 +2,10 @@
// 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
/*
This example demonstrates how to parse TOML from a file and // This example demonstrates how to parse TOML from a file and re-serialize it (print it out) to stdout.
re-serialize it (print it out) to stdout.
*/ #include "examples.h"
#include <iostream>
#include "utf8_console.h"
#define TOML_UNRELEASED_FEATURES 1 #define TOML_UNRELEASED_FEATURES 1
#include <toml++/toml.h> #include <toml++/toml.h>
@ -18,14 +14,13 @@ using namespace std::string_view_literals;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
std::ios_base::sync_with_stdio(false); examples::init();
init_utf8_console();
auto path = std::string{ argc > 1 ? argv[1] : "example.toml" }; const auto path = argc > 1 ? std::string_view{ argv[1] } : "example.toml"sv;
try try
{ {
const auto tbl = toml::parse_file(path); const auto table = toml::parse_file(path);
std::cout << tbl << "\n"; std::cout << table << "\n";
} }
catch (const toml::parse_error& err) catch (const toml::parse_error& err)
{ {

View File

@ -52,5 +52,11 @@
<ItemGroup> <ItemGroup>
<Natvis Include="..\toml++.natvis" /> <Natvis Include="..\toml++.natvis" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project> </Project>

View File

@ -2,17 +2,10 @@
// 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
/*
This example demonstrates some slightly advanced techniques // This example demonstrates the use of some more advanced features to generate a tree of random TOML data.
being used to randomly generate a tree of TOML data.
*/ #include "examples.h"
#include <iostream>
#include <sstream>
#include <array>
#include <ctime>
#include "utf8_console.h"
#define TOML_PARSER 0 #define TOML_PARSER 0
#include <toml++/toml.h> #include <toml++/toml.h>
@ -63,7 +56,7 @@ namespace
[[nodiscard]] [[nodiscard]]
static T rand(T excl_max) noexcept static T rand(T excl_max) noexcept
{ {
return static_cast<T>(static_cast<T>(::rand()) % excl_max); return static_cast<T>(static_cast<T>(std::rand()) % excl_max);
} }
template <typename T> template <typename T>
@ -107,12 +100,9 @@ namespace
} }
} }
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
std::ios_base::sync_with_stdio(false); examples::init();
init_utf8_console();
srand(static_cast<unsigned int>(time(nullptr)));
int node_budget{}; int node_budget{};
for (int i = 1; i < argc; i++) for (int i = 1; i < argc; i++)
@ -132,34 +122,48 @@ int main(int argc, char** argv)
int container_min_values = 10; int container_min_values = 10;
bool in_arr = false; bool in_arr = false;
const auto add = [&](auto&& obj) noexcept -> toml::node& const auto add = [&](auto&& val) noexcept -> auto&
{ {
using value_ref = decltype(val);
using value_type = std::remove_reference_t<value_ref>;
using node_type = toml::inserted_type_of<value_type>;
toml::node* new_node{}; toml::node* new_node{};
// we're adding an element to an array
if (auto arr = tree.back()->as_array()) if (auto arr = tree.back()->as_array())
{ {
arr->push_back(std::forward<decltype(obj)>(obj)); arr->push_back(std::forward<value_ref>(val));
new_node = &arr->back(); new_node = &arr->back();
} }
else
new_node = &(*tree.back()->ref<toml::table>().insert_or_assign(
rand_string(rand<size_t>(1u, 4u), '-'),
std::forward<decltype(obj)>(obj)
).first).second;
if constexpr (toml::is_array<decltype(obj)> || toml::is_table<decltype(obj)>) // we're adding a new kvp to a table
else
{
auto& table = tree.back()->ref<toml::table>();
const auto it = table.insert_or_assign(
rand_string(rand<size_t>(1u, 4u), '-'),
std::forward<value_ref>(val)
);
new_node = &it.first->second;
}
// we added a new array or table, so now we need to step into it
if constexpr (toml::is_container<value_type>)
{ {
tree.push_back(new_node); tree.push_back(new_node);
container_min_values = rand(1, 4); container_min_values = rand(1, 4);
in_arr = toml::is_array<decltype(obj)>; in_arr = toml::is_array<value_type>;
if constexpr (toml::is_array<decltype(obj)>) if constexpr (toml::is_array<value_type>)
tree.back()->as_array()->reserve(static_cast<size_t>(container_min_values)); tree.back()->as_array()->reserve(static_cast<size_t>(container_min_values));
} }
else else
container_min_values--; container_min_values--;
node_budget--; node_budget--;
return *new_node; return *new_node->as<node_type>();
}; };
while (node_budget) while (node_budget)
@ -167,7 +171,7 @@ int main(int argc, char** argv)
if (!in_arr && rand(100) >= 75) if (!in_arr && rand(100) >= 75)
{ {
if (container_min_values <= 0 && tree.size() < max_depth) if (container_min_values <= 0 && tree.size() < max_depth)
add(toml::table{}).ref<toml::table>().is_inline(tree.size() >= max_depth - 2u && rand(100) >= 85); add(toml::table{}).is_inline(tree.size() >= max_depth - 2u && rand(100) >= 85);
} }
else else
{ {
@ -179,41 +183,41 @@ int main(int argc, char** argv)
switch (new_node_type) switch (new_node_type)
{ {
case toml::node_type::array: case toml::node_type::array:
if (container_min_values <= 0 && tree.size() < max_depth) if (container_min_values <= 0 && tree.size() < max_depth)
add(toml::array{}); add(toml::array{});
break; break;
case toml::node_type::string: case toml::node_type::string:
add(rand_string(rand<size_t>(8u))); add(rand_string(rand<size_t>(8u)));
break; break;
case toml::node_type::integer: case toml::node_type::integer:
add(rand()); add(rand());
break; break;
case toml::node_type::floating_point: case toml::node_type::floating_point:
add(rand(10001u) / 10000.0); add(rand(10001u) / 10000.0);
break; break;
case toml::node_type::boolean: case toml::node_type::boolean:
add(!rand(2u)); add(!rand(2u));
break; break;
case toml::node_type::date: case toml::node_type::date:
add(rand_date()); add(rand_date());
break; break;
case toml::node_type::time: case toml::node_type::time:
add(rand_time()); add(rand_time());
break; break;
case toml::node_type::date_time: case toml::node_type::date_time:
add(rand(100) >= 75 add(rand(100) >= 75
? toml::date_time{ rand_date(), rand_time() } ? toml::date_time{ rand_date(), rand_time() }
: toml::date_time{ rand_date(), rand_time(), toml::time_offset{ rand<int8_t>(-11, 12), rand<int8_t>(-45, +46) } } : toml::date_time{ rand_date(), rand_time(), toml::time_offset{ rand<int8_t>(-11, 12), rand<int8_t>(-45, +46) } }
); );
break; break;
} }
if (container_min_values <= 0 && tree.size() >= 2u && rand(100) >= 85) if (container_min_values <= 0 && tree.size() >= 2u && rand(100) >= 85)
{ {

View File

@ -52,5 +52,11 @@
<ItemGroup> <ItemGroup>
<None Include="meson.build" /> <None Include="meson.build" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project> </Project>

View File

@ -2,14 +2,10 @@
// 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
/*
This example demonstrates how to use the toml::json_formatter to // This example demonstrates how to use the toml::json_formatter to re-serialize TOML data as JSON.
re-serialize TOML data as JSON.
*/ #include "examples.h"
#include <iostream>
#include "utf8_console.h"
#define TOML_UNRELEASED_FEATURES 1 #define TOML_UNRELEASED_FEATURES 1
#include <toml++/toml.h> #include <toml++/toml.h>
@ -18,38 +14,28 @@ using namespace std::string_view_literals;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
std::ios_base::sync_with_stdio(false); examples::init();
init_utf8_console();
// read from a file if a path argument is given toml::table table;
if (argc > 1) try
{ {
try
{ // read from a file if a path argument is given
const auto table = toml::parse_file(argv[1]); if (argc > 1)
std::cout << toml::json_formatter{ table } << "\n"; table = toml::parse_file(argv[1]);
}
catch (const toml::parse_error& err) // otherwise read directly from stdin
{ else
std::cerr << err << "\n"; table = toml::parse(std::cin, "stdin"sv);
return 1;
} std::cout << toml::json_formatter{ table } << "\n";
} }
catch (const toml::parse_error& err)
// otherwise read directly from stdin {
else std::cerr << err << "\n";
{ return 1;
try
{
const auto table = toml::parse(std::cin, "stdin"sv);
std::cout << toml::json_formatter{ table } << "\n";
}
catch (const toml::parse_error& err)
{
std::cerr << err << "\n";
return 1;
}
} }
std::cout << toml::json_formatter{ table } << "\n";
return 0; return 0;
} }

View File

@ -52,5 +52,11 @@
<ItemGroup> <ItemGroup>
<None Include="meson.build" /> <None Include="meson.build" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project> </Project>

View File

@ -1,18 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#endif
inline void init_utf8_console() noexcept
{
#ifdef _WIN32
SetConsoleOutputCP(65001); //CP_UTF8
#endif
std::cout << std::boolalpha;
}

View File

@ -176,78 +176,6 @@ TOML_IMPL_NAMESPACE_START
TOML_ENABLE_WARNINGS; TOML_ENABLE_WARNINGS;
}; };
template <typename T>
[[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node_specialized(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
static_assert(!std::is_same_v<type, node>);
static_assert(!is_node_view<type>);
if constexpr (is_one_of<type, array, table>)
{
return new type{ static_cast<T&&>(val) };
}
else if constexpr (is_native<type> && !std::is_same_v<remove_cvref_t<T>, type>)
{
return new value<type>{ static_cast<T&&>(val) };
}
else
{
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<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<T>>;
if constexpr (is_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
return new value<value_type>{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
return new value<value_type>{ static_cast<T&&>(val) };
}
}
template <typename T>
[[nodiscard]]
auto* make_node(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
if constexpr (std::is_same_v<type, node> || is_node_view<type>)
{
if constexpr (is_node_view<type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return static_cast<T&&>(val).visit([](auto&& concrete) noexcept
{
return static_cast<toml::node*>(make_node_specialized(std::forward<decltype(concrete)>(concrete)));
});
}
else
return make_node_specialized(static_cast<T&&>(val));
}
template <typename T>
[[nodiscard]]
auto* make_node(inserter<T>&& val) noexcept
{
return make_node(std::move(val.value));
}
} }
TOML_IMPL_NAMESPACE_END; TOML_IMPL_NAMESPACE_END;
/// \endcond /// \endcond
@ -330,7 +258,7 @@ TOML_NAMESPACE_START
if (!val) if (!val)
return; return;
} }
elements.emplace_back(impl::make_node(std::forward<T>(val))); elements.emplace_back(impl::make_node(static_cast<T&&>(val)));
} }
#if TOML_LIFETIME_HOOKS #if TOML_LIFETIME_HOOKS
@ -418,11 +346,11 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals) explicit array(ElemType&& val, ElemTypes&&... vals)
{ {
elements.reserve(sizeof...(ElemTypes) + 1_sz); elements.reserve(sizeof...(ElemTypes) + 1_sz);
emplace_back_if_not_empty_view(std::forward<ElemType>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val));
if constexpr (sizeof...(ElemTypes) > 0) if constexpr (sizeof...(ElemTypes) > 0)
{ {
( (
emplace_back_if_not_empty_view(std::forward<ElemTypes>(vals)), emplace_back_if_not_empty_view(static_cast<ElemTypes&&>(vals)),
... ...
); );
} }
@ -544,7 +472,7 @@ TOML_NAMESPACE_START
if (!val) if (!val)
return end(); return end();
} }
return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) }; return { elements.emplace(pos.raw_, impl::make_node(static_cast<ElemType&&>(val))) };
} }
/// \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.
@ -595,7 +523,7 @@ 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, std::forward<ElemType>(val)); case 1: return insert(pos, static_cast<ElemType&&>(val));
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());
@ -605,7 +533,7 @@ TOML_NAMESPACE_START
elements[i].reset(impl::make_node(val)); elements[i].reset(impl::make_node(val));
//# potentially move the initial value into the last element //# potentially move the initial value into the last element
elements[i].reset(impl::make_node(std::forward<ElemType>(val))); elements[i].reset(impl::make_node(static_cast<ElemType&&>(val)));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
} }
@ -714,7 +642,7 @@ TOML_NAMESPACE_START
TOML_SA_UNWRAPPED_NODE_TYPE_LIST TOML_SA_UNWRAPPED_NODE_TYPE_LIST
); );
return { elements.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<Args>(args)...} ) }; return { elements.emplace(pos.raw_, new impl::wrap_node<type>{ static_cast<Args&&>(args)...} ) };
} }
/// \brief Removes the specified element from the array. /// \brief Removes the specified element from the array.
@ -800,7 +728,7 @@ TOML_NAMESPACE_START
else if (new_size < elements.size()) else if (new_size < elements.size())
elements.resize(new_size); elements.resize(new_size);
else if (new_size > elements.size()) else if (new_size > elements.size())
insert(cend(), new_size - elements.size(), std::forward<ElemType>(default_init_val)); insert(cend(), new_size - elements.size(), static_cast<ElemType&&>(default_init_val));
} }
/// \brief Shrinks the array to the given size. /// \brief Shrinks the array to the given size.
@ -851,7 +779,7 @@ TOML_NAMESPACE_START
template <typename ElemType> template <typename ElemType>
void push_back(ElemType&& val) noexcept void push_back(ElemType&& val) noexcept
{ {
emplace_back_if_not_empty_view(std::forward<ElemType>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val));
} }
/// \brief Emplaces a new element at the end of the array. /// \brief Emplaces a new element at the end of the array.
@ -885,7 +813,7 @@ TOML_NAMESPACE_START
TOML_SA_UNWRAPPED_NODE_TYPE_LIST TOML_SA_UNWRAPPED_NODE_TYPE_LIST
); );
auto nde = new impl::wrap_node<type>{ std::forward<Args>(args)... }; auto nde = new impl::wrap_node<type>{ static_cast<Args&&>(args)... };
elements.emplace_back(nde); elements.emplace_back(nde);
return *nde; return *nde;
} }

View File

@ -549,47 +549,64 @@ TOML_IMPL_NAMESPACE_END;
TOML_NAMESPACE_START TOML_NAMESPACE_START
{ {
/// \brief Metafunction for determining if a type is a toml::table. /// \brief Metafunction for determining if a type is, or is a reference to, a toml::table.
template <typename T> template <typename T>
inline constexpr bool is_table = std::is_same_v<impl::remove_cvref_t<T>, table>; inline constexpr bool is_table = std::is_same_v<impl::remove_cvref_t<T>, table>;
/// \brief Metafunction for determining if a type is a toml::array. /// \brief Metafunction for determining if a type is, or is a reference to, a toml::array.
template <typename T> template <typename T>
inline constexpr bool is_array = std::is_same_v<impl::remove_cvref_t<T>, array>; inline constexpr bool is_array = std::is_same_v<impl::remove_cvref_t<T>, array>;
/// \brief Metafunction for determining if a type is a std::string or toml::value<std::string>. /// \brief Metafunction for determining if a type satisfies either toml::is_table or toml::is_array.
template <typename T>
inline constexpr bool is_container = is_table<T> || is_array<T>;
/// \brief Metafunction for determining if a type is, or is a reference to, a std::string or toml::value<std::string>.
template <typename T> template <typename T>
inline constexpr bool is_string = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<std::string>>; inline constexpr bool is_string = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<std::string>>;
/// \brief Metafunction for determining if a type is an int64_t or toml::value<int64_t>. /// \brief Metafunction for determining if a type is, or is a reference to, a int64_t or toml::value<int64_t>.
template <typename T> template <typename T>
inline constexpr bool is_integer = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<int64_t>>; inline constexpr bool is_integer = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<int64_t>>;
/// \brief Metafunction for determining if a type is a double or toml::value<double>. /// \brief Metafunction for determining if a type is, or is a reference to, a double or toml::value<double>.
template <typename T> template <typename T>
inline constexpr bool is_floating_point = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<double>>; inline constexpr bool is_floating_point = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<double>>;
/// \brief Metafunction for determining if a type satisfies `toml::is_integer || toml::is_floating_point`. /// \brief Metafunction for determining if a type satisfies either toml::is_integer or toml::is_floating_point.
template <typename T> template <typename T>
inline constexpr bool is_number = is_integer<T> || is_floating_point<T>; inline constexpr bool is_number = is_integer<T> || is_floating_point<T>;
/// \brief Metafunction for determining if a type is a bool toml::value<bool>. /// \brief Metafunction for determining if a type is, or is a reference to, a bool or toml::value<bool>.
template <typename T> template <typename T>
inline constexpr bool is_boolean = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<bool>>; inline constexpr bool is_boolean = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<bool>>;
/// \brief Metafunction for determining if a type is a toml::date or toml::value<date>. /// \brief Metafunction for determining if a type is, or is a reference to, a toml::date or toml::value<date>.
template <typename T> template <typename T>
inline constexpr bool is_date = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date>>; inline constexpr bool is_date = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date>>;
/// \brief Metafunction for determining if a type is a toml::time or toml::value<time>. /// \brief Metafunction for determining if a type is, or is a reference to, a toml::time or toml::value<time>.
template <typename T> template <typename T>
inline constexpr bool is_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<time>>; inline constexpr bool is_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<time>>;
/// \brief Metafunction for determining if a type is a toml::date_time or toml::value<date_time>. /// \brief Metafunction for determining if a type is, or is a reference to, a toml::date_time or toml::value<date_time>.
template <typename T> template <typename T>
inline constexpr bool is_date_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date_time>>; inline constexpr bool is_date_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date_time>>;
/// \brief Metafunction for determining if a type is a toml::node_view. /// \brief Metafunction for determining if a type satisfies any of toml::is_date, toml::is_time or toml::is_date_time.
template <typename T>
inline constexpr bool is_chronological = is_date<T> || is_time<T> || is_date_time<T>;
/// \brief Metafunction for determining if a type is, or is a reference to, any of the toml value types. Excludes tables and arrays.
template <typename T>
inline constexpr bool is_value = is_string<T> || is_number<T> || is_boolean<T> || is_chronological<T>;
/// \brief Metafunction for determining if a type is, or is a reference to, a toml::node (or one of its subclasses).
template <typename T>
inline constexpr bool is_node = std::is_same_v<toml::node, impl::remove_cvref_t<T>>
|| std::is_base_of_v<toml::node, impl::remove_cvref_t<T>>;
/// \brief Metafunction for determining if a type is, or is a reference to, a toml::node_view.
template <typename T> template <typename T>
inline constexpr bool is_node_view = impl::is_one_of<impl::remove_cvref_t<T>, node_view<node>, node_view<const node>>; inline constexpr bool is_node_view = impl::is_one_of<impl::remove_cvref_t<T>, node_view<node>, node_view<const node>>;
} }
@ -618,6 +635,8 @@ TOML_IMPL_NAMESPACE_START
TOML_ATTR(pure) TOML_ATTR(pure)
inline fp_class fpclassify(const double& val) noexcept inline fp_class fpclassify(const double& val) noexcept
{ {
static_assert(sizeof(uint64_t) == sizeof(double));
constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull; constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull; constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull; constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;
@ -693,12 +712,105 @@ TOML_IMPL_NAMESPACE_START
"time"sv, "time"sv,
"date-time"sv "date-time"sv
}; };
template <typename T>
[[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node_specialized(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
static_assert(!std::is_same_v<type, node>);
static_assert(!is_node_view<type>);
if constexpr (is_one_of<type, array, table>)
{
return new type{ static_cast<T&&>(val) };
}
else if constexpr (is_native<type> && !std::is_same_v<remove_cvref_t<T>, type>)
{
return new value<type>{ static_cast<T&&>(val) };
}
else
{
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<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<T>>;
if constexpr (is_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
return new value<value_type>{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
return new value<value_type>{ static_cast<T&&>(val) };
}
}
template <typename T>
[[nodiscard]]
auto* make_node(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
if constexpr (std::is_same_v<type, node> || is_node_view<type>)
{
if constexpr (is_node_view<type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return static_cast<T&&>(val).visit([](auto&& concrete) noexcept
{
return static_cast<toml::node*>(make_node_specialized(static_cast<decltype(concrete)&&>(concrete)));
});
}
else
return make_node_specialized(static_cast<T&&>(val));
}
template <typename T>
[[nodiscard]]
auto* make_node(inserter<T>&& val) noexcept
{
return make_node(static_cast<T&&>(val.value));
}
template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
struct inserted_type_of_
{
using type = std::remove_pointer_t<decltype(make_node(std::declval<T>()))>;
};
template <typename T>
struct inserted_type_of_<inserter<T>, false>
{
using type = typename inserted_type_of_<T>::type;
};
template <typename T>
struct inserted_type_of_<T, false>
{
using type = void;
};
} }
TOML_IMPL_NAMESPACE_END; TOML_IMPL_NAMESPACE_END;
/// \endcond /// \endcond
TOML_NAMESPACE_START TOML_NAMESPACE_START
{ {
/// \brief Metafunction for determining which toml node type would be constructed
// if an object of this type was inserted into a toml::table or toml::array.
template <typename T>
using inserted_type_of = typename impl::inserted_type_of_<impl::remove_cvref_t<T>>::type;
[[nodiscard]] [[nodiscard]]
TOML_ATTR(const) TOML_ATTR(const)
TOML_ALWAYS_INLINE TOML_ALWAYS_INLINE

View File

@ -89,9 +89,9 @@ TOML_NAMESPACE_START
&& "template type argument T provided to toml::node::ref() didn't match the node's actual type" && "template type argument T provided to toml::node::ref() didn't match the node's actual type"
); );
if constexpr (impl::is_native<type>) if constexpr (impl::is_native<type>)
return std::forward<N>(n).template ref_cast<type>().get(); return static_cast<N&&>(n).template ref_cast<type>().get();
else else
return std::forward<N>(n).template ref_cast<type>(); return static_cast<N&&>(n).template ref_cast<type>();
} }
/// \endcond /// \endcond
@ -737,47 +737,47 @@ TOML_NAMESPACE_START
{ {
case node_type::table: case node_type::table:
if constexpr (can_visit<Func&&, N&&, table>) if constexpr (can_visit<Func&&, N&&, table>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<table>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<table>());
break; break;
case node_type::array: case node_type::array:
if constexpr (can_visit<Func&&, N&&, array>) if constexpr (can_visit<Func&&, N&&, array>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<array>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<array>());
break; break;
case node_type::string: case node_type::string:
if constexpr (can_visit<Func&&, N&&, std::string>) if constexpr (can_visit<Func&&, N&&, std::string>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<std::string>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<std::string>());
break; break;
case node_type::integer: case node_type::integer:
if constexpr (can_visit<Func&&, N&&, int64_t>) if constexpr (can_visit<Func&&, N&&, int64_t>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<int64_t>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<int64_t>());
break; break;
case node_type::floating_point: case node_type::floating_point:
if constexpr (can_visit<Func&&, N&&, double>) if constexpr (can_visit<Func&&, N&&, double>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<double>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<double>());
break; break;
case node_type::boolean: case node_type::boolean:
if constexpr (can_visit<Func&&, N&&, bool>) if constexpr (can_visit<Func&&, N&&, bool>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<bool>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<bool>());
break; break;
case node_type::date: case node_type::date:
if constexpr (can_visit<Func&&, N&&, date>) if constexpr (can_visit<Func&&, N&&, date>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<date>());
break; break;
case node_type::time: case node_type::time:
if constexpr (can_visit<Func&&, N&&, time>) if constexpr (can_visit<Func&&, N&&, time>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<time>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<time>());
break; break;
case node_type::date_time: case node_type::date_time:
if constexpr (can_visit<Func&&, N&&, date_time>) if constexpr (can_visit<Func&&, N&&, date_time>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date_time>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<date_time>());
break; break;
case node_type::none: TOML_UNREACHABLE; case node_type::none: TOML_UNREACHABLE;
@ -850,7 +850,7 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) & decltype(auto) visit(Func&& visitor) &
noexcept(visit_is_nothrow<Func&&, node&>) noexcept(visit_is_nothrow<Func&&, node&>)
{ {
return do_visit(*this, std::forward<Func>(visitor)); return do_visit(*this, static_cast<Func&&>(visitor));
} }
/// \brief Invokes a visitor on the node based on the node's concrete type (rvalue overload). /// \brief Invokes a visitor on the node based on the node's concrete type (rvalue overload).
@ -858,7 +858,7 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) && decltype(auto) visit(Func&& visitor) &&
noexcept(visit_is_nothrow<Func&&, node&&>) noexcept(visit_is_nothrow<Func&&, node&&>)
{ {
return do_visit(std::move(*this), std::forward<Func>(visitor)); return do_visit(static_cast<node&&>(*this), static_cast<Func&&>(visitor));
} }
/// \brief Invokes a visitor on the node based on the node's concrete type (const lvalue overload). /// \brief Invokes a visitor on the node based on the node's concrete type (const lvalue overload).
@ -866,7 +866,7 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) const& decltype(auto) visit(Func&& visitor) const&
noexcept(visit_is_nothrow<Func&&, const node&>) noexcept(visit_is_nothrow<Func&&, const node&>)
{ {
return do_visit(*this, std::forward<Func>(visitor)); return do_visit(*this, static_cast<Func&&>(visitor));
} }
/// @} /// @}

View File

@ -396,8 +396,8 @@ TOML_NAMESPACE_START
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
if (node_) if (node_)
return node_->value_or(std::forward<T>(default_value)); return node_->value_or(static_cast<T&&>(default_value));
return std::wstring{ std::forward<T>(default_value) }; return std::wstring{ static_cast<T&&>(default_value) };
#else #else
@ -414,11 +414,11 @@ TOML_NAMESPACE_START
>; >;
if (node_) if (node_)
return node_->value_or(std::forward<T>(default_value)); return node_->value_or(static_cast<T&&>(default_value));
if constexpr (std::is_pointer_v<value_type>) if constexpr (std::is_pointer_v<value_type>)
return value_type{ default_value }; return value_type{ default_value };
else else
return std::forward<T>(default_value); return static_cast<T&&>(default_value);
} }
} }
@ -467,9 +467,9 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) const decltype(auto) visit(Func&& visitor) const
noexcept(visit_is_nothrow<Func&&>) noexcept(visit_is_nothrow<Func&&>)
{ {
using return_type = decltype(node_->visit(std::forward<Func>(visitor))); using return_type = decltype(node_->visit(static_cast<Func&&>(visitor)));
if (node_) if (node_)
return node_->visit(std::forward<Func>(visitor)); return node_->visit(static_cast<Func&&>(visitor));
if constexpr (!std::is_void_v<return_type>) if constexpr (!std::is_void_v<return_type>)
return return_type{}; return return_type{};
} }

View File

@ -155,19 +155,19 @@ TOML_IMPL_NAMESPACE_START
template <typename V> template <typename V>
table_init_pair(std::string&& k, V&& v) noexcept table_init_pair(std::string&& k, V&& v) noexcept
: key{ std::move(k) }, : key{ std::move(k) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(std::string_view k, V&& v) noexcept table_init_pair(std::string_view k, V&& v) noexcept
: key{ k }, : key{ k },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(const char* k, V&& v) noexcept table_init_pair(const char* k, V&& v) noexcept
: key{ k }, : key{ k },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
@ -175,19 +175,19 @@ TOML_IMPL_NAMESPACE_START
template <typename V> template <typename V>
table_init_pair(std::wstring&& k, V&& v) noexcept table_init_pair(std::wstring&& k, V&& v) noexcept
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(std::wstring_view k, V&& v) noexcept table_init_pair(std::wstring_view k, V&& v) noexcept
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(const wchar_t* k, V&& v) noexcept table_init_pair(const wchar_t* k, V&& v) noexcept
: key{ narrow(std::wstring_view{ k }) }, : key{ narrow(std::wstring_view{ k }) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
#endif #endif

View File

@ -216,14 +216,14 @@ TOML_IMPL_NAMESPACE_START
template <typename U, typename String = std::string_view> template <typename U, typename String = std::string_view>
explicit utf8_reader(U && source, String&& source_path = {}) explicit utf8_reader(U && source, String&& source_path = {})
noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>) noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
: stream{ std::forward<U>(source) } : stream{ static_cast<U&&>(source) }
{ {
std::memset(codepoints, 0, sizeof(codepoints)); std::memset(codepoints, 0, sizeof(codepoints));
codepoints[0].position = { 1, 1 }; codepoints[0].position = { 1, 1 };
codepoints[1].position = { 1, 1 }; codepoints[1].position = { 1, 1 };
if (!source_path.empty()) if (!source_path.empty())
source_path_ = std::make_shared<const std::string>(std::forward<String>(source_path)); source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
} }
[[nodiscard]] [[nodiscard]]

View File

@ -79,7 +79,7 @@ TOML_IMPL_NAMESPACE_START
[[nodiscard]] [[nodiscard]]
static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>) static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
{ {
return T(std::forward<Args>(args)...); return T(static_cast<Args&&>(args)...);
} }
}; };
@ -91,7 +91,7 @@ TOML_IMPL_NAMESPACE_START
TOML_ALWAYS_INLINE TOML_ALWAYS_INLINE
static U&& make(U&& val) noexcept static U&& make(U&& val) noexcept
{ {
return std::forward<U>(val); return static_cast<U&&>(val);
} }
}; };
@ -112,7 +112,7 @@ TOML_IMPL_NAMESPACE_START
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
if constexpr (is_wide_string<T>) if constexpr (is_wide_string<T>)
return narrow(std::forward<T>(arg)); return narrow(static_cast<T&&>(arg));
#endif // TOML_WINDOWS_COMPAT #endif // TOML_WINDOWS_COMPAT
} }
}; };
@ -244,9 +244,9 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit value(Args&&... args) explicit value(Args&&... args)
noexcept(noexcept(value_type( noexcept(noexcept(value_type(
impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...) impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...)
))) )))
: val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...)) : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))
{ {
#if TOML_LIFETIME_HOOKS #if TOML_LIFETIME_HOOKS
lh_ctor(); lh_ctor();
@ -406,21 +406,21 @@ TOML_NAMESPACE_START
/// \brief Returns a reference to the underlying value. /// \brief Returns a reference to the underlying value.
[[nodiscard]] value_type& get() & noexcept { return val_; } [[nodiscard]] value_type& get() & noexcept { return val_; }
/// \brief Returns a reference to the underlying value (rvalue overload). /// \brief Returns a reference to the underlying value (rvalue overload).
[[nodiscard]] value_type&& get() && noexcept { return std::move(val_); } [[nodiscard]] value_type&& get() && noexcept { return static_cast<value_type&&>(val_); }
/// \brief Returns a reference to the underlying value (const overload). /// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] const value_type& get() const & noexcept { return val_; } [[nodiscard]] const value_type& get() const & noexcept { return val_; }
/// \brief Returns a reference to the underlying value. /// \brief Returns a reference to the underlying value.
[[nodiscard]] value_type& operator* () & noexcept { return val_; } [[nodiscard]] value_type& operator* () & noexcept { return val_; }
/// \brief Returns a reference to the underlying value (rvalue overload). /// \brief Returns a reference to the underlying value (rvalue overload).
[[nodiscard]] value_type&& operator* () && noexcept { return std::move(val_); } [[nodiscard]] value_type&& operator* () && noexcept { return static_cast<value_type&&>(val_); }
/// \brief Returns a reference to the underlying value (const overload). /// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] const value_type& operator* () const& noexcept { return val_; } [[nodiscard]] const value_type& operator* () const& noexcept { return val_; }
/// \brief Returns a reference to the underlying value. /// \brief Returns a reference to the underlying value.
[[nodiscard]] explicit operator value_type& () & noexcept { return val_; } [[nodiscard]] explicit operator value_type& () & noexcept { return val_; }
/// \brief Returns a reference to the underlying value (rvalue overload). /// \brief Returns a reference to the underlying value (rvalue overload).
[[nodiscard]] explicit operator value_type && () && noexcept { return std::move(val_); } [[nodiscard]] explicit operator value_type && () && noexcept { return static_cast<value_type&&>(val_); }
/// \brief Returns a reference to the underlying value (const overload). /// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; } [[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; }
@ -843,7 +843,7 @@ TOML_NAMESPACE_START
if (type() == node_type::string) if (type() == node_type::string)
return widen(*ref_cast<std::string>()); return widen(*ref_cast<std::string>());
return std::wstring{ std::forward<T>(default_value) }; return std::wstring{ static_cast<T&&>(default_value) };
#else #else
@ -911,7 +911,7 @@ TOML_NAMESPACE_START
if constexpr (std::is_pointer_v<value_type>) if constexpr (std::is_pointer_v<value_type>)
return value_type{ default_value }; return value_type{ default_value };
else else
return std::forward<T>(default_value); return static_cast<T&&>(default_value);
} }
} }
} }

View File

@ -274,6 +274,35 @@ namespace toml
CHECK_VALUE_OR( const std::wstring&&, std::wstring); CHECK_VALUE_OR( const std::wstring&&, std::wstring);
#endif #endif
#define CHECK_INSERTED_AS(T, expected) \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<const T>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T&>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<const T&>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T&&>>)
CHECK_INSERTED_AS(table, table);
CHECK_INSERTED_AS(array, array);
CHECK_INSERTED_AS(node, node);
CHECK_INSERTED_AS(time, value<time>);
CHECK_INSERTED_AS(date, value<date>);
CHECK_INSERTED_AS(date_time, value<date_time>);
CHECK_INSERTED_AS(bool, value<bool>);
CHECK_INSERTED_AS(int8_t, value<int64_t>);
CHECK_INSERTED_AS(int16_t, value<int64_t>);
CHECK_INSERTED_AS(int32_t, value<int64_t>);
CHECK_INSERTED_AS(int64_t, value<int64_t>);
CHECK_INSERTED_AS(uint8_t, value<int64_t>);
CHECK_INSERTED_AS(uint16_t, value<int64_t>);
CHECK_INSERTED_AS(uint32_t, value<int64_t>);
CHECK_INSERTED_AS(float, value<double>);
CHECK_INSERTED_AS(double, value<double>);
#ifdef TOML_FP16
CHECK_INSERTED_AS(TOML_FP16, value<double>);
#endif
#ifdef TOML_FLOAT16
CHECK_INSERTED_AS(TOML_FLOAT16, value<double>);
#endif
static_assert(is_same_v<decltype(declval<node&>().ref<double>()), double&>); static_assert(is_same_v<decltype(declval<node&>().ref<double>()), double&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<double>()), double&&>); static_assert(is_same_v<decltype(declval<node&&>().ref<double>()), double&&>);

View File

@ -69,6 +69,10 @@
<None Include=".gitattributes" /> <None Include=".gitattributes" />
<None Include=".gitignore" /> <None Include=".gitignore" />
<None Include=".runsettings" /> <None Include=".runsettings" />
<None Include="cmake\install-rules.cmake" />
<None Include="cmake\project-is-top-level.cmake" />
<None Include="cmake\tomlplusplusConfig.cmake" />
<None Include="cmake\variables.cmake" />
<None Include="CODE_OF_CONDUCT.md" /> <None Include="CODE_OF_CONDUCT.md" />
<None Include="CONTRIBUTING.md" /> <None Include="CONTRIBUTING.md" />
<None Include="cpp.hint" /> <None Include="cpp.hint" />

View File

@ -119,6 +119,18 @@
<Filter>docs</Filter> <Filter>docs</Filter>
</None> </None>
<None Include=".runsettings" /> <None Include=".runsettings" />
<None Include="cmake\install-rules.cmake">
<Filter>cmake</Filter>
</None>
<None Include="cmake\project-is-top-level.cmake">
<Filter>cmake</Filter>
</None>
<None Include="cmake\tomlplusplusConfig.cmake">
<Filter>cmake</Filter>
</None>
<None Include="cmake\variables.cmake">
<Filter>cmake</Filter>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include=".circleci"> <Filter Include=".circleci">
@ -136,6 +148,9 @@
<Filter Include="docs\pages"> <Filter Include="docs\pages">
<UniqueIdentifier>{9bdc71ff-34f1-4312-9f15-1850d4c5908b}</UniqueIdentifier> <UniqueIdentifier>{9bdc71ff-34f1-4312-9f15-1850d4c5908b}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="cmake">
<UniqueIdentifier>{47351d16-986b-4f4b-bd5e-b7c66a7a68d3}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Natvis Include="toml++.natvis" /> <Natvis Include="toml++.natvis" />

275
toml.hpp
View File

@ -1244,6 +1244,9 @@ TOML_NAMESPACE_START
template <typename T> template <typename T>
inline constexpr bool is_array = std::is_same_v<impl::remove_cvref_t<T>, array>; inline constexpr bool is_array = std::is_same_v<impl::remove_cvref_t<T>, array>;
template <typename T>
inline constexpr bool is_container = is_table<T> || is_array<T>;
template <typename T> template <typename T>
inline constexpr bool is_string = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<std::string>>; inline constexpr bool is_string = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<std::string>>;
@ -1268,6 +1271,16 @@ TOML_NAMESPACE_START
template <typename T> template <typename T>
inline constexpr bool is_date_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date_time>>; inline constexpr bool is_date_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date_time>>;
template <typename T>
inline constexpr bool is_chronological = is_date<T> || is_time<T> || is_date_time<T>;
template <typename T>
inline constexpr bool is_value = is_string<T> || is_number<T> || is_boolean<T> || is_chronological<T>;
template <typename T>
inline constexpr bool is_node = std::is_same_v<toml::node, impl::remove_cvref_t<T>>
|| std::is_base_of_v<toml::node, impl::remove_cvref_t<T>>;
template <typename T> template <typename T>
inline constexpr bool is_node_view = impl::is_one_of<impl::remove_cvref_t<T>, node_view<node>, node_view<const node>>; inline constexpr bool is_node_view = impl::is_one_of<impl::remove_cvref_t<T>, node_view<node>, node_view<const node>>;
} }
@ -1291,6 +1304,8 @@ TOML_IMPL_NAMESPACE_START
TOML_ATTR(pure) TOML_ATTR(pure)
inline fp_class fpclassify(const double& val) noexcept inline fp_class fpclassify(const double& val) noexcept
{ {
static_assert(sizeof(uint64_t) == sizeof(double));
constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull; constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull; constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull; constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;
@ -1366,11 +1381,103 @@ TOML_IMPL_NAMESPACE_START
"time"sv, "time"sv,
"date-time"sv "date-time"sv
}; };
template <typename T>
[[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node_specialized(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
static_assert(!std::is_same_v<type, node>);
static_assert(!is_node_view<type>);
if constexpr (is_one_of<type, array, table>)
{
return new type{ static_cast<T&&>(val) };
}
else if constexpr (is_native<type> && !std::is_same_v<remove_cvref_t<T>, type>)
{
return new value<type>{ static_cast<T&&>(val) };
}
else
{
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<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<T>>;
if constexpr (is_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
return new value<value_type>{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
return new value<value_type>{ static_cast<T&&>(val) };
}
}
template <typename T>
[[nodiscard]]
auto* make_node(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
if constexpr (std::is_same_v<type, node> || is_node_view<type>)
{
if constexpr (is_node_view<type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return static_cast<T&&>(val).visit([](auto&& concrete) noexcept
{
return static_cast<toml::node*>(make_node_specialized(static_cast<decltype(concrete)&&>(concrete)));
});
}
else
return make_node_specialized(static_cast<T&&>(val));
}
template <typename T>
[[nodiscard]]
auto* make_node(inserter<T>&& val) noexcept
{
return make_node(static_cast<T&&>(val.value));
}
template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
struct inserted_type_of_
{
using type = std::remove_pointer_t<decltype(make_node(std::declval<T>()))>;
};
template <typename T>
struct inserted_type_of_<inserter<T>, false>
{
using type = typename inserted_type_of_<T>::type;
};
template <typename T>
struct inserted_type_of_<T, false>
{
using type = void;
};
} }
TOML_IMPL_NAMESPACE_END; TOML_IMPL_NAMESPACE_END;
TOML_NAMESPACE_START TOML_NAMESPACE_START
{ {
// if an object of this type was inserted into a toml::table or toml::array.
template <typename T>
using inserted_type_of = typename impl::inserted_type_of_<impl::remove_cvref_t<T>>::type;
[[nodiscard]] [[nodiscard]]
TOML_ATTR(const) TOML_ATTR(const)
TOML_ALWAYS_INLINE TOML_ALWAYS_INLINE
@ -2363,9 +2470,9 @@ TOML_NAMESPACE_START
&& "template type argument T provided to toml::node::ref() didn't match the node's actual type" && "template type argument T provided to toml::node::ref() didn't match the node's actual type"
); );
if constexpr (impl::is_native<type>) if constexpr (impl::is_native<type>)
return std::forward<N>(n).template ref_cast<type>().get(); return static_cast<N&&>(n).template ref_cast<type>().get();
else else
return std::forward<N>(n).template ref_cast<type>(); return static_cast<N&&>(n).template ref_cast<type>();
} }
protected: protected:
@ -2667,47 +2774,47 @@ TOML_NAMESPACE_START
{ {
case node_type::table: case node_type::table:
if constexpr (can_visit<Func&&, N&&, table>) if constexpr (can_visit<Func&&, N&&, table>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<table>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<table>());
break; break;
case node_type::array: case node_type::array:
if constexpr (can_visit<Func&&, N&&, array>) if constexpr (can_visit<Func&&, N&&, array>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<array>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<array>());
break; break;
case node_type::string: case node_type::string:
if constexpr (can_visit<Func&&, N&&, std::string>) if constexpr (can_visit<Func&&, N&&, std::string>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<std::string>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<std::string>());
break; break;
case node_type::integer: case node_type::integer:
if constexpr (can_visit<Func&&, N&&, int64_t>) if constexpr (can_visit<Func&&, N&&, int64_t>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<int64_t>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<int64_t>());
break; break;
case node_type::floating_point: case node_type::floating_point:
if constexpr (can_visit<Func&&, N&&, double>) if constexpr (can_visit<Func&&, N&&, double>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<double>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<double>());
break; break;
case node_type::boolean: case node_type::boolean:
if constexpr (can_visit<Func&&, N&&, bool>) if constexpr (can_visit<Func&&, N&&, bool>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<bool>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<bool>());
break; break;
case node_type::date: case node_type::date:
if constexpr (can_visit<Func&&, N&&, date>) if constexpr (can_visit<Func&&, N&&, date>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<date>());
break; break;
case node_type::time: case node_type::time:
if constexpr (can_visit<Func&&, N&&, time>) if constexpr (can_visit<Func&&, N&&, time>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<time>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<time>());
break; break;
case node_type::date_time: case node_type::date_time:
if constexpr (can_visit<Func&&, N&&, date_time>) if constexpr (can_visit<Func&&, N&&, date_time>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date_time>()); return static_cast<Func&&>(visitor)(static_cast<N&&>(n).template ref_cast<date_time>());
break; break;
case node_type::none: TOML_UNREACHABLE; case node_type::none: TOML_UNREACHABLE;
@ -2747,21 +2854,21 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) & decltype(auto) visit(Func&& visitor) &
noexcept(visit_is_nothrow<Func&&, node&>) noexcept(visit_is_nothrow<Func&&, node&>)
{ {
return do_visit(*this, std::forward<Func>(visitor)); return do_visit(*this, static_cast<Func&&>(visitor));
} }
template <typename Func> template <typename Func>
decltype(auto) visit(Func&& visitor) && decltype(auto) visit(Func&& visitor) &&
noexcept(visit_is_nothrow<Func&&, node&&>) noexcept(visit_is_nothrow<Func&&, node&&>)
{ {
return do_visit(std::move(*this), std::forward<Func>(visitor)); return do_visit(static_cast<node&&>(*this), static_cast<Func&&>(visitor));
} }
template <typename Func> template <typename Func>
decltype(auto) visit(Func&& visitor) const& decltype(auto) visit(Func&& visitor) const&
noexcept(visit_is_nothrow<Func&&, const node&>) noexcept(visit_is_nothrow<Func&&, const node&>)
{ {
return do_visit(*this, std::forward<Func>(visitor)); return do_visit(*this, static_cast<Func&&>(visitor));
} }
[[nodiscard]] explicit operator node_view<node>() noexcept; [[nodiscard]] explicit operator node_view<node>() noexcept;
@ -2846,7 +2953,7 @@ TOML_IMPL_NAMESPACE_START
[[nodiscard]] [[nodiscard]]
static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>) static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
{ {
return T(std::forward<Args>(args)...); return T(static_cast<Args&&>(args)...);
} }
}; };
@ -2858,7 +2965,7 @@ TOML_IMPL_NAMESPACE_START
TOML_ALWAYS_INLINE TOML_ALWAYS_INLINE
static U&& make(U&& val) noexcept static U&& make(U&& val) noexcept
{ {
return std::forward<U>(val); return static_cast<U&&>(val);
} }
}; };
@ -2879,7 +2986,7 @@ TOML_IMPL_NAMESPACE_START
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
if constexpr (is_wide_string<T>) if constexpr (is_wide_string<T>)
return narrow(std::forward<T>(arg)); return narrow(static_cast<T&&>(arg));
#endif // TOML_WINDOWS_COMPAT #endif // TOML_WINDOWS_COMPAT
} }
}; };
@ -2985,9 +3092,9 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
explicit value(Args&&... args) explicit value(Args&&... args)
noexcept(noexcept(value_type( noexcept(noexcept(value_type(
impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...) impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...)
))) )))
: val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...)) : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))
{ {
#if TOML_LIFETIME_HOOKS #if TOML_LIFETIME_HOOKS
lh_ctor(); lh_ctor();
@ -3114,15 +3221,15 @@ TOML_NAMESPACE_START
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); } [[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); }
[[nodiscard]] value_type& get() & noexcept { return val_; } [[nodiscard]] value_type& get() & noexcept { return val_; }
[[nodiscard]] value_type&& get() && noexcept { return std::move(val_); } [[nodiscard]] value_type&& get() && noexcept { return static_cast<value_type&&>(val_); }
[[nodiscard]] const value_type& get() const & noexcept { return val_; } [[nodiscard]] const value_type& get() const & noexcept { return val_; }
[[nodiscard]] value_type& operator* () & noexcept { return val_; } [[nodiscard]] value_type& operator* () & noexcept { return val_; }
[[nodiscard]] value_type&& operator* () && noexcept { return std::move(val_); } [[nodiscard]] value_type&& operator* () && noexcept { return static_cast<value_type&&>(val_); }
[[nodiscard]] const value_type& operator* () const& noexcept { return val_; } [[nodiscard]] const value_type& operator* () const& noexcept { return val_; }
[[nodiscard]] explicit operator value_type& () & noexcept { return val_; } [[nodiscard]] explicit operator value_type& () & noexcept { return val_; }
[[nodiscard]] explicit operator value_type && () && noexcept { return std::move(val_); } [[nodiscard]] explicit operator value_type && () && noexcept { return static_cast<value_type&&>(val_); }
[[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; } [[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; }
[[nodiscard]] value_flags flags() const noexcept [[nodiscard]] value_flags flags() const noexcept
@ -3467,7 +3574,7 @@ TOML_NAMESPACE_START
if (type() == node_type::string) if (type() == node_type::string)
return widen(*ref_cast<std::string>()); return widen(*ref_cast<std::string>());
return std::wstring{ std::forward<T>(default_value) }; return std::wstring{ static_cast<T&&>(default_value) };
#else #else
@ -3535,7 +3642,7 @@ TOML_NAMESPACE_START
if constexpr (std::is_pointer_v<value_type>) if constexpr (std::is_pointer_v<value_type>)
return value_type{ default_value }; return value_type{ default_value };
else else
return std::forward<T>(default_value); return static_cast<T&&>(default_value);
} }
} }
} }
@ -3767,78 +3874,6 @@ TOML_IMPL_NAMESPACE_START
TOML_ENABLE_WARNINGS; TOML_ENABLE_WARNINGS;
}; };
template <typename T>
[[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node_specialized(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
static_assert(!std::is_same_v<type, node>);
static_assert(!is_node_view<type>);
if constexpr (is_one_of<type, array, table>)
{
return new type{ static_cast<T&&>(val) };
}
else if constexpr (is_native<type> && !std::is_same_v<remove_cvref_t<T>, type>)
{
return new value<type>{ static_cast<T&&>(val) };
}
else
{
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<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<T>>;
if constexpr (is_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
return new value<value_type>{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
return new value<value_type>{ static_cast<T&&>(val) };
}
}
template <typename T>
[[nodiscard]]
auto* make_node(T&& val) noexcept
{
using type = unwrap_node<remove_cvref_t<T>>;
if constexpr (std::is_same_v<type, node> || is_node_view<type>)
{
if constexpr (is_node_view<type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return static_cast<T&&>(val).visit([](auto&& concrete) noexcept
{
return static_cast<toml::node*>(make_node_specialized(std::forward<decltype(concrete)>(concrete)));
});
}
else
return make_node_specialized(static_cast<T&&>(val));
}
template <typename T>
[[nodiscard]]
auto* make_node(inserter<T>&& val) noexcept
{
return make_node(std::move(val.value));
}
} }
TOML_IMPL_NAMESPACE_END; TOML_IMPL_NAMESPACE_END;
@ -3865,7 +3900,7 @@ TOML_NAMESPACE_START
if (!val) if (!val)
return; return;
} }
elements.emplace_back(impl::make_node(std::forward<T>(val))); elements.emplace_back(impl::make_node(static_cast<T&&>(val)));
} }
#if TOML_LIFETIME_HOOKS #if TOML_LIFETIME_HOOKS
@ -3907,11 +3942,11 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals) explicit array(ElemType&& val, ElemTypes&&... vals)
{ {
elements.reserve(sizeof...(ElemTypes) + 1_sz); elements.reserve(sizeof...(ElemTypes) + 1_sz);
emplace_back_if_not_empty_view(std::forward<ElemType>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val));
if constexpr (sizeof...(ElemTypes) > 0) if constexpr (sizeof...(ElemTypes) > 0)
{ {
( (
emplace_back_if_not_empty_view(std::forward<ElemTypes>(vals)), emplace_back_if_not_empty_view(static_cast<ElemTypes&&>(vals)),
... ...
); );
} }
@ -3975,7 +4010,7 @@ TOML_NAMESPACE_START
if (!val) if (!val)
return end(); return end();
} }
return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) }; return { elements.emplace(pos.raw_, impl::make_node(static_cast<ElemType&&>(val))) };
} }
template <typename ElemType> template <typename ElemType>
@ -3989,7 +4024,7 @@ 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, std::forward<ElemType>(val)); case 1: return insert(pos, static_cast<ElemType&&>(val));
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());
@ -3998,7 +4033,7 @@ TOML_NAMESPACE_START
for (size_t e = start_idx + count - 1_sz; i < e; i++) for (size_t e = start_idx + count - 1_sz; i < e; i++)
elements[i].reset(impl::make_node(val)); elements[i].reset(impl::make_node(val));
elements[i].reset(impl::make_node(std::forward<ElemType>(val))); elements[i].reset(impl::make_node(static_cast<ElemType&&>(val)));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
} }
@ -4057,7 +4092,7 @@ TOML_NAMESPACE_START
TOML_SA_UNWRAPPED_NODE_TYPE_LIST TOML_SA_UNWRAPPED_NODE_TYPE_LIST
); );
return { elements.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<Args>(args)...} ) }; return { elements.emplace(pos.raw_, new impl::wrap_node<type>{ static_cast<Args&&>(args)...} ) };
} }
iterator erase(const_iterator pos) noexcept; iterator erase(const_iterator pos) noexcept;
@ -4076,7 +4111,7 @@ TOML_NAMESPACE_START
else if (new_size < elements.size()) else if (new_size < elements.size())
elements.resize(new_size); elements.resize(new_size);
else if (new_size > elements.size()) else if (new_size > elements.size())
insert(cend(), new_size - elements.size(), std::forward<ElemType>(default_init_val)); insert(cend(), new_size - elements.size(), static_cast<ElemType&&>(default_init_val));
} }
void truncate(size_t new_size); void truncate(size_t new_size);
@ -4084,7 +4119,7 @@ TOML_NAMESPACE_START
template <typename ElemType> template <typename ElemType>
void push_back(ElemType&& val) noexcept void push_back(ElemType&& val) noexcept
{ {
emplace_back_if_not_empty_view(std::forward<ElemType>(val)); emplace_back_if_not_empty_view(static_cast<ElemType&&>(val));
} }
template <typename ElemType, typename... Args> template <typename ElemType, typename... Args>
@ -4097,7 +4132,7 @@ TOML_NAMESPACE_START
TOML_SA_UNWRAPPED_NODE_TYPE_LIST TOML_SA_UNWRAPPED_NODE_TYPE_LIST
); );
auto nde = new impl::wrap_node<type>{ std::forward<Args>(args)... }; auto nde = new impl::wrap_node<type>{ static_cast<Args&&>(args)... };
elements.emplace_back(nde); elements.emplace_back(nde);
return *nde; return *nde;
} }
@ -4338,19 +4373,19 @@ TOML_IMPL_NAMESPACE_START
template <typename V> template <typename V>
table_init_pair(std::string&& k, V&& v) noexcept table_init_pair(std::string&& k, V&& v) noexcept
: key{ std::move(k) }, : key{ std::move(k) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(std::string_view k, V&& v) noexcept table_init_pair(std::string_view k, V&& v) noexcept
: key{ k }, : key{ k },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(const char* k, V&& v) noexcept table_init_pair(const char* k, V&& v) noexcept
: key{ k }, : key{ k },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
@ -4358,19 +4393,19 @@ TOML_IMPL_NAMESPACE_START
template <typename V> template <typename V>
table_init_pair(std::wstring&& k, V&& v) noexcept table_init_pair(std::wstring&& k, V&& v) noexcept
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(std::wstring_view k, V&& v) noexcept table_init_pair(std::wstring_view k, V&& v) noexcept
: key{ narrow(k) }, : key{ narrow(k) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
template <typename V> template <typename V>
table_init_pair(const wchar_t* k, V&& v) noexcept table_init_pair(const wchar_t* k, V&& v) noexcept
: key{ narrow(std::wstring_view{ k }) }, : key{ narrow(std::wstring_view{ k }) },
value{ make_node(std::forward<V>(v)) } value{ make_node(static_cast<V&&>(v)) }
{} {}
#endif #endif
@ -4920,8 +4955,8 @@ TOML_NAMESPACE_START
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
if (node_) if (node_)
return node_->value_or(std::forward<T>(default_value)); return node_->value_or(static_cast<T&&>(default_value));
return std::wstring{ std::forward<T>(default_value) }; return std::wstring{ static_cast<T&&>(default_value) };
#else #else
@ -4938,11 +4973,11 @@ TOML_NAMESPACE_START
>; >;
if (node_) if (node_)
return node_->value_or(std::forward<T>(default_value)); return node_->value_or(static_cast<T&&>(default_value));
if constexpr (std::is_pointer_v<value_type>) if constexpr (std::is_pointer_v<value_type>)
return value_type{ default_value }; return value_type{ default_value };
else else
return std::forward<T>(default_value); return static_cast<T&&>(default_value);
} }
} }
@ -4961,9 +4996,9 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) const decltype(auto) visit(Func&& visitor) const
noexcept(visit_is_nothrow<Func&&>) noexcept(visit_is_nothrow<Func&&>)
{ {
using return_type = decltype(node_->visit(std::forward<Func>(visitor))); using return_type = decltype(node_->visit(static_cast<Func&&>(visitor)));
if (node_) if (node_)
return node_->visit(std::forward<Func>(visitor)); return node_->visit(static_cast<Func&&>(visitor));
if constexpr (!std::is_void_v<return_type>) if constexpr (!std::is_void_v<return_type>)
return return_type{}; return return_type{};
} }
@ -6685,14 +6720,14 @@ TOML_IMPL_NAMESPACE_START
template <typename U, typename String = std::string_view> template <typename U, typename String = std::string_view>
explicit utf8_reader(U && source, String&& source_path = {}) explicit utf8_reader(U && source, String&& source_path = {})
noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>) noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
: stream{ std::forward<U>(source) } : stream{ static_cast<U&&>(source) }
{ {
std::memset(codepoints, 0, sizeof(codepoints)); std::memset(codepoints, 0, sizeof(codepoints));
codepoints[0].position = { 1, 1 }; codepoints[0].position = { 1, 1 };
codepoints[1].position = { 1, 1 }; codepoints[1].position = { 1, 1 };
if (!source_path.empty()) if (!source_path.empty())
source_path_ = std::make_shared<const std::string>(std::forward<String>(source_path)); source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
} }
[[nodiscard]] [[nodiscard]]