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

View File

@ -51,5 +51,11 @@
<ItemGroup>
<None Include="meson.build" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<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>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
/*
This example demonstrates how to parse TOML from a file and
re-serialize it (print it out) to stdout.
// This example demonstrates how to parse TOML from a file and re-serialize it (print it out) to stdout.
*/
#include <iostream>
#include "utf8_console.h"
#include "examples.h"
#define TOML_UNRELEASED_FEATURES 1
#include <toml++/toml.h>
@ -18,14 +14,13 @@ using namespace std::string_view_literals;
int main(int argc, char** argv)
{
std::ios_base::sync_with_stdio(false);
init_utf8_console();
examples::init();
auto path = std::string{ argc > 1 ? argv[1] : "example.toml" };
const auto path = argc > 1 ? std::string_view{ argv[1] } : "example.toml"sv;
try
{
const auto tbl = toml::parse_file(path);
std::cout << tbl << "\n";
const auto table = toml::parse_file(path);
std::cout << table << "\n";
}
catch (const toml::parse_error& err)
{

View File

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

View File

@ -2,17 +2,10 @@
// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
/*
This example demonstrates some slightly advanced techniques
being used to randomly generate a tree of TOML data.
// This example demonstrates the use of some more advanced features to generate a tree of random TOML data.
*/
#include <iostream>
#include <sstream>
#include <array>
#include <ctime>
#include "utf8_console.h"
#include "examples.h"
#define TOML_PARSER 0
#include <toml++/toml.h>
@ -63,7 +56,7 @@ namespace
[[nodiscard]]
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>
@ -107,12 +100,9 @@ namespace
}
}
int main(int argc, char** argv)
{
std::ios_base::sync_with_stdio(false);
init_utf8_console();
srand(static_cast<unsigned int>(time(nullptr)));
examples::init();
int node_budget{};
for (int i = 1; i < argc; i++)
@ -132,34 +122,48 @@ int main(int argc, char** argv)
int container_min_values = 10;
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{};
// we're adding an element to an 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();
}
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);
container_min_values = rand(1, 4);
in_arr = toml::is_array<decltype(obj)>;
if constexpr (toml::is_array<decltype(obj)>)
in_arr = toml::is_array<value_type>;
if constexpr (toml::is_array<value_type>)
tree.back()->as_array()->reserve(static_cast<size_t>(container_min_values));
}
else
container_min_values--;
node_budget--;
return *new_node;
return *new_node->as<node_type>();
};
while (node_budget)
@ -167,7 +171,7 @@ int main(int argc, char** argv)
if (!in_arr && rand(100) >= 75)
{
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
{
@ -179,41 +183,41 @@ int main(int argc, char** argv)
switch (new_node_type)
{
case toml::node_type::array:
if (container_min_values <= 0 && tree.size() < max_depth)
add(toml::array{});
break;
case toml::node_type::array:
if (container_min_values <= 0 && tree.size() < max_depth)
add(toml::array{});
break;
case toml::node_type::string:
add(rand_string(rand<size_t>(8u)));
break;
case toml::node_type::string:
add(rand_string(rand<size_t>(8u)));
break;
case toml::node_type::integer:
add(rand());
break;
case toml::node_type::integer:
add(rand());
break;
case toml::node_type::floating_point:
add(rand(10001u) / 10000.0);
break;
case toml::node_type::floating_point:
add(rand(10001u) / 10000.0);
break;
case toml::node_type::boolean:
add(!rand(2u));
break;
case toml::node_type::boolean:
add(!rand(2u));
break;
case toml::node_type::date:
add(rand_date());
break;
case toml::node_type::date:
add(rand_date());
break;
case toml::node_type::time:
add(rand_time());
break;
case toml::node_type::time:
add(rand_time());
break;
case toml::node_type::date_time:
add(rand(100) >= 75
? 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) } }
);
break;
case toml::node_type::date_time:
add(rand(100) >= 75
? 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) } }
);
break;
}
if (container_min_values <= 0 && tree.size() >= 2u && rand(100) >= 85)
{

View File

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

View File

@ -2,14 +2,10 @@
// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
/*
This example demonstrates how to use the toml::json_formatter to
re-serialize TOML data as JSON.
// This example demonstrates how to use the toml::json_formatter to re-serialize TOML data as JSON.
*/
#include <iostream>
#include "utf8_console.h"
#include "examples.h"
#define TOML_UNRELEASED_FEATURES 1
#include <toml++/toml.h>
@ -18,38 +14,28 @@ using namespace std::string_view_literals;
int main(int argc, char** argv)
{
std::ios_base::sync_with_stdio(false);
init_utf8_console();
examples::init();
// read from a file if a path argument is given
if (argc > 1)
toml::table table;
try
{
try
{
const auto table = toml::parse_file(argv[1]);
std::cout << toml::json_formatter{ table } << "\n";
}
catch (const toml::parse_error& err)
{
std::cerr << err << "\n";
return 1;
}
}
// otherwise read directly from stdin
else
{
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;
}
// read from a file if a path argument is given
if (argc > 1)
table = toml::parse_file(argv[1]);
// otherwise read directly from stdin
else
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;
}

View File

@ -52,5 +52,11 @@
<ItemGroup>
<None Include="meson.build" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<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;
};
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;
/// \endcond
@ -330,7 +258,7 @@ TOML_NAMESPACE_START
if (!val)
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
@ -418,11 +346,11 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals)
{
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)
{
(
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)
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.
@ -595,7 +523,7 @@ TOML_NAMESPACE_START
switch (count)
{
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:
{
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));
//# 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) };
}
}
@ -714,7 +642,7 @@ TOML_NAMESPACE_START
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.
@ -800,7 +728,7 @@ TOML_NAMESPACE_START
else if (new_size < elements.size())
elements.resize(new_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.
@ -851,7 +779,7 @@ TOML_NAMESPACE_START
template <typename ElemType>
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.
@ -885,7 +813,7 @@ TOML_NAMESPACE_START
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);
return *nde;
}

View File

@ -549,47 +549,64 @@ TOML_IMPL_NAMESPACE_END;
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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)
inline fp_class fpclassify(const double& val) noexcept
{
static_assert(sizeof(uint64_t) == sizeof(double));
constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;
@ -693,12 +712,105 @@ TOML_IMPL_NAMESPACE_START
"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;
/// \endcond
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]]
TOML_ATTR(const)
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"
);
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
return std::forward<N>(n).template ref_cast<type>();
return static_cast<N&&>(n).template ref_cast<type>();
}
/// \endcond
@ -737,47 +737,47 @@ TOML_NAMESPACE_START
{
case node_type::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;
case node_type::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;
case node_type::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;
case node_type::integer:
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;
case node_type::floating_point:
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;
case node_type::boolean:
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;
case node_type::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;
case node_type::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;
case node_type::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;
case node_type::none: TOML_UNREACHABLE;
@ -850,7 +850,7 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) &
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).
@ -858,7 +858,7 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) &&
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).
@ -866,7 +866,7 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) const&
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 (node_)
return node_->value_or(std::forward<T>(default_value));
return std::wstring{ std::forward<T>(default_value) };
return node_->value_or(static_cast<T&&>(default_value));
return std::wstring{ static_cast<T&&>(default_value) };
#else
@ -414,11 +414,11 @@ TOML_NAMESPACE_START
>;
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>)
return value_type{ default_value };
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
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_)
return node_->visit(std::forward<Func>(visitor));
return node_->visit(static_cast<Func&&>(visitor));
if constexpr (!std::is_void_v<return_type>)
return return_type{};
}

View File

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

View File

@ -216,14 +216,14 @@ TOML_IMPL_NAMESPACE_START
template <typename U, typename String = std::string_view>
explicit utf8_reader(U && source, String&& source_path = {})
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));
codepoints[0].position = { 1, 1 };
codepoints[1].position = { 1, 1 };
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]]

View File

@ -79,7 +79,7 @@ TOML_IMPL_NAMESPACE_START
[[nodiscard]]
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
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 constexpr (is_wide_string<T>)
return narrow(std::forward<T>(arg));
return narrow(static_cast<T&&>(arg));
#endif // TOML_WINDOWS_COMPAT
}
};
@ -244,9 +244,9 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR
explicit value(Args&&... args)
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
lh_ctor();
@ -406,21 +406,21 @@ TOML_NAMESPACE_START
/// \brief Returns a reference to the underlying value.
[[nodiscard]] value_type& get() & noexcept { return val_; }
/// \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).
[[nodiscard]] const value_type& get() const & noexcept { return val_; }
/// \brief Returns a reference to the underlying value.
[[nodiscard]] value_type& operator* () & noexcept { return val_; }
/// \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).
[[nodiscard]] const value_type& operator* () const& noexcept { return val_; }
/// \brief Returns a reference to the underlying value.
[[nodiscard]] explicit operator value_type& () & noexcept { return val_; }
/// \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).
[[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; }
@ -843,7 +843,7 @@ TOML_NAMESPACE_START
if (type() == node_type::string)
return widen(*ref_cast<std::string>());
return std::wstring{ std::forward<T>(default_value) };
return std::wstring{ static_cast<T&&>(default_value) };
#else
@ -911,7 +911,7 @@ TOML_NAMESPACE_START
if constexpr (std::is_pointer_v<value_type>)
return value_type{ default_value };
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);
#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&&>);

View File

@ -69,6 +69,10 @@
<None Include=".gitattributes" />
<None Include=".gitignore" />
<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="CONTRIBUTING.md" />
<None Include="cpp.hint" />

View File

@ -119,6 +119,18 @@
<Filter>docs</Filter>
</None>
<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>
<Filter Include=".circleci">
@ -136,6 +148,9 @@
<Filter Include="docs\pages">
<UniqueIdentifier>{9bdc71ff-34f1-4312-9f15-1850d4c5908b}</UniqueIdentifier>
</Filter>
<Filter Include="cmake">
<UniqueIdentifier>{47351d16-986b-4f4b-bd5e-b7c66a7a68d3}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

275
toml.hpp
View File

@ -1244,6 +1244,9 @@ TOML_NAMESPACE_START
template <typename T>
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>
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>
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>
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)
inline fp_class fpclassify(const double& val) noexcept
{
static_assert(sizeof(uint64_t) == sizeof(double));
constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;
@ -1366,11 +1381,103 @@ TOML_IMPL_NAMESPACE_START
"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_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]]
TOML_ATTR(const)
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"
);
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
return std::forward<N>(n).template ref_cast<type>();
return static_cast<N&&>(n).template ref_cast<type>();
}
protected:
@ -2667,47 +2774,47 @@ TOML_NAMESPACE_START
{
case node_type::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;
case node_type::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;
case node_type::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;
case node_type::integer:
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;
case node_type::floating_point:
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;
case node_type::boolean:
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;
case node_type::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;
case node_type::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;
case node_type::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;
case node_type::none: TOML_UNREACHABLE;
@ -2747,21 +2854,21 @@ TOML_NAMESPACE_START
decltype(auto) visit(Func&& visitor) &
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>
decltype(auto) visit(Func&& visitor) &&
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>
decltype(auto) visit(Func&& visitor) const&
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;
@ -2846,7 +2953,7 @@ TOML_IMPL_NAMESPACE_START
[[nodiscard]]
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
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 constexpr (is_wide_string<T>)
return narrow(std::forward<T>(arg));
return narrow(static_cast<T&&>(arg));
#endif // TOML_WINDOWS_COMPAT
}
};
@ -2985,9 +3092,9 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR
explicit value(Args&&... args)
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
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]] 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]] 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]] 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]] value_flags flags() const noexcept
@ -3467,7 +3574,7 @@ TOML_NAMESPACE_START
if (type() == node_type::string)
return widen(*ref_cast<std::string>());
return std::wstring{ std::forward<T>(default_value) };
return std::wstring{ static_cast<T&&>(default_value) };
#else
@ -3535,7 +3642,7 @@ TOML_NAMESPACE_START
if constexpr (std::is_pointer_v<value_type>)
return value_type{ default_value };
else
return std::forward<T>(default_value);
return static_cast<T&&>(default_value);
}
}
}
@ -3767,78 +3874,6 @@ TOML_IMPL_NAMESPACE_START
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;
@ -3865,7 +3900,7 @@ TOML_NAMESPACE_START
if (!val)
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
@ -3907,11 +3942,11 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals)
{
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)
{
(
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)
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>
@ -3989,7 +4024,7 @@ TOML_NAMESPACE_START
switch (count)
{
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:
{
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++)
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) };
}
}
@ -4057,7 +4092,7 @@ TOML_NAMESPACE_START
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;
@ -4076,7 +4111,7 @@ TOML_NAMESPACE_START
else if (new_size < elements.size())
elements.resize(new_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);
@ -4084,7 +4119,7 @@ TOML_NAMESPACE_START
template <typename ElemType>
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>
@ -4097,7 +4132,7 @@ TOML_NAMESPACE_START
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);
return *nde;
}
@ -4338,19 +4373,19 @@ TOML_IMPL_NAMESPACE_START
template <typename V>
table_init_pair(std::string&& k, V&& v) noexcept
: key{ std::move(k) },
value{ make_node(std::forward<V>(v)) }
value{ make_node(static_cast<V&&>(v)) }
{}
template <typename V>
table_init_pair(std::string_view k, V&& v) noexcept
: key{ k },
value{ make_node(std::forward<V>(v)) }
value{ make_node(static_cast<V&&>(v)) }
{}
template <typename V>
table_init_pair(const char* k, V&& v) noexcept
: key{ k },
value{ make_node(std::forward<V>(v)) }
value{ make_node(static_cast<V&&>(v)) }
{}
#if TOML_WINDOWS_COMPAT
@ -4358,19 +4393,19 @@ TOML_IMPL_NAMESPACE_START
template <typename V>
table_init_pair(std::wstring&& k, V&& v) noexcept
: key{ narrow(k) },
value{ make_node(std::forward<V>(v)) }
value{ make_node(static_cast<V&&>(v)) }
{}
template <typename V>
table_init_pair(std::wstring_view k, V&& v) noexcept
: key{ narrow(k) },
value{ make_node(std::forward<V>(v)) }
value{ make_node(static_cast<V&&>(v)) }
{}
template <typename V>
table_init_pair(const wchar_t* k, V&& v) noexcept
: key{ narrow(std::wstring_view{ k }) },
value{ make_node(std::forward<V>(v)) }
value{ make_node(static_cast<V&&>(v)) }
{}
#endif
@ -4920,8 +4955,8 @@ TOML_NAMESPACE_START
#if TOML_WINDOWS_COMPAT
if (node_)
return node_->value_or(std::forward<T>(default_value));
return std::wstring{ std::forward<T>(default_value) };
return node_->value_or(static_cast<T&&>(default_value));
return std::wstring{ static_cast<T&&>(default_value) };
#else
@ -4938,11 +4973,11 @@ TOML_NAMESPACE_START
>;
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>)
return value_type{ default_value };
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
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_)
return node_->visit(std::forward<Func>(visitor));
return node_->visit(static_cast<Func&&>(visitor));
if constexpr (!std::is_void_v<return_type>)
return return_type{};
}
@ -6685,14 +6720,14 @@ TOML_IMPL_NAMESPACE_START
template <typename U, typename String = std::string_view>
explicit utf8_reader(U && source, String&& source_path = {})
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));
codepoints[0].position = { 1, 1 };
codepoints[1].position = { 1, 1 };
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]]