Skip to content

Commit

Permalink
fixed #197
Browse files Browse the repository at this point in the history
also:
- fixed `noexcept(...)` sometimes being incorrectly derived on `for_each()
- refactors
  • Loading branch information
marzer committed Sep 5, 2023
1 parent 882d9d1 commit d46cac7
Show file tree
Hide file tree
Showing 60 changed files with 1,064 additions and 445 deletions.
5 changes: 3 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ tab_width = 4
end_of_line = lf
trim_trailing_whitespace = true
charset = utf-8
max_line_length = 120

[*.{md,markdown}]
trim_trailing_whitespace = false

[*.{gitattributes,yaml,yml,vcxproj,vcxproj.filters,sln,rc,clang-format,toml}]
[*.{gitattributes,yaml,yml,vcxproj,vcxproj.filters,sln,rc,clang-format,toml,py,cmake}]
indent_style = space

[{Doxyfile,Doxyfile-mcss}]
[{Doxyfile,Doxyfile-mcss,CMakeLists.txt}]
indent_style = space

[*.{hlsl,rc,sln,vcxproj,vcxproj.filters}]
Expand Down
12 changes: 6 additions & 6 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@

*.cs eol=lf diff=csharp

*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

*.doc binary
*.DOC binary
*.docx binary
*.DOCX binary
*.pdf binary
*.PDF binary
*.ai binary
*.bin binary
*.bmp binary
Expand Down
32 changes: 14 additions & 18 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,36 @@
Thanks for contributing!
-->



**What does this change do?**

<!--
Changes all Foos to Bars.
--->



**Is it related to an exisiting bug report or feature request?**

<!--
Fixes #69.
--->



**Pre-merge checklist**

<!--
Not all of these will necessarily apply, particularly if you're not making a code change (e.g. fixing documentation).
That's OK. Tick the ones that do by placing an x in them, e.g. [x]
--->
- [ ] I've read [CONTRIBUTING.md]
- [ ] I've rebased my changes against the current HEAD of `origin/master` (if necessary)
- [ ] I've added new test cases to verify my change
- [ ] I've regenerated toml.hpp ([how-to])
- [ ] I've updated any affected documentation
- [ ] I've rebuilt and run the tests with at least one of:
- [ ] Clang 6 or higher
- [ ] GCC 7 or higher
- [ ] MSVC 19.20 (Visual Studio 2019) or higher
- [ ] I've added my name to the list of contributors in [README.md](https://github.com/marzer/tomlplusplus/blob/master/README.md)


- [ ] I've read [CONTRIBUTING.md]
- [ ] I've rebased my changes against the current HEAD of `origin/master` (if necessary)
- [ ] I've added new test cases to verify my change
- [ ] I've regenerated toml.hpp ([how-to])
- [ ] I've updated any affected documentation
- [ ] I've rebuilt and run the tests with at least one of:
- [ ] Clang 8 or higher
- [ ] GCC 8 or higher
- [ ] MSVC 19.20 (Visual Studio 2019) or higher
- [ ] I've added my name to the list of contributors in [README.md](https://github.com/marzer/tomlplusplus/blob/master/README.md)

[CONTRIBUTING.md]: https://github.com/marzer/tomlplusplus/blob/master/CONTRIBUTING.md
[how-to]: https://github.com/marzer/tomlplusplus/blob/master/CONTRIBUTING.md#regenerating-tomlhpp
[README.md]: https://github.com/marzer/tomlplusplus/blob/master/README.md
[README.md]: https://github.com/marzer/tomlplusplus/blob/master/README.md
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ template:
- fixed `toml::value::flags()` not being cleared when `std::move`-ing a value
- fixed error in README (#195) (@andrewkcorcoran)
- fixed compiler error when using NVCC (#198) (@thompsonnoahe)
- fixed `noexcept(...)` sometimes being incorrectly derived on `for_each()`
- fixed `for_each()` compilation error on GCC &lt;= 7 (#197) (@sagi-ottopia)

#### Changes:

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
- C++17 (plus some C++20 features where available, e.g. experimental support for [char8_t] strings)
- Doesn't require RTTI
- Works with or without exceptions
- Tested on Clang (6+), GCC (7+) and MSVC (VS2019)
- Tested on Clang (8+), GCC (8+) and MSVC (VS2019)
- Tested on x64, x86 and ARM

<br>
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/main_page.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- C++17 (plus some C++20 features where available, e.g. experimental support for char8_t strings)
- Doesn't require RTTI
- Works with or without exceptions
- Tested on Clang (6+), GCC (7+) and MSVC (VS2019)
- Tested on Clang (8+), GCC (8+) and MSVC (VS2019)
- Tested on x64, x86 and ARM

<!-- --------------------------------------------------------------------------------------------------------------- -->
Expand Down
147 changes: 105 additions & 42 deletions include/toml++/impl/array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@
#include "make_node.hpp"
#include "header_start.hpp"

#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
#if TOML_GCC && TOML_GCC <= 7
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 1
#else
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 0
#endif
#endif

#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE \
"If you're seeing this error it's because you're using one of toml++'s for_each() functions on a compiler with " \
"known bugs in that area (e.g. GCC 7). On these compilers returning a bool (or bool-convertible) value from the " \
"for_each() callable causes spurious compilation failures, while returning nothing (void) works fine. " \
"If you believe this message is incorrect for your compiler, you can try your luck by #defining " \
"TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it works, great! Let me know at " \
"https://github.com/marzer/tomlplusplus/issues. Alternatively, if you don't have any need for early-exiting from " \
"for_each(), you can suppress this error by #defining TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED " \
"and moving on with your life."
#endif

/// \cond
TOML_IMPL_NAMESPACE_START
{
Expand Down Expand Up @@ -834,51 +854,56 @@ TOML_NAMESPACE_START
using for_each_elem_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Array>;

template <typename Func, typename Array, typename T>
static constexpr bool can_for_each = std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t> //
|| std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>> //
|| std::is_invocable_v<Func, for_each_elem_ref<T, Array>>;
using can_for_each = std::disjunction<std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
std::is_invocable<Func, for_each_elem_ref<T, Array>>>;

template <typename Func, typename Array, typename T>
static constexpr bool can_for_each_nothrow =
std::is_nothrow_invocable_v<Func, for_each_elem_ref<T, Array>, size_t> //
|| std::is_nothrow_invocable_v<Func, size_t, for_each_elem_ref<T, Array>> //
|| std::is_nothrow_invocable_v<Func, for_each_elem_ref<T, Array>>;
using can_for_each_nothrow = std::conditional_t<
// first form
std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
std::conditional_t<
// second form
std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
std::conditional_t<
// third form
std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>,
std::false_type>>>;

template <typename Func, typename Array>
static constexpr bool can_for_each_any = can_for_each<Func, Array, table> //
|| can_for_each<Func, Array, array> //
|| can_for_each<Func, Array, std::string> //
|| can_for_each<Func, Array, int64_t> //
|| can_for_each<Func, Array, double> //
|| can_for_each<Func, Array, bool> //
|| can_for_each<Func, Array, date> //
|| can_for_each<Func, Array, time> //
|| can_for_each<Func, Array, date_time>;
using can_for_each_any = std::disjunction<can_for_each<Func, Array, table>,
can_for_each<Func, Array, array>,
can_for_each<Func, Array, std::string>,
can_for_each<Func, Array, int64_t>,
can_for_each<Func, Array, double>,
can_for_each<Func, Array, bool>,
can_for_each<Func, Array, date>,
can_for_each<Func, Array, time>,
can_for_each<Func, Array, date_time>>;

template <typename Func, typename Array, typename T>
static constexpr bool for_each_is_nothrow_one = !can_for_each<Func, Array, T> //
|| can_for_each_nothrow<Func, Array, T>;

// clang-format off

using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Array, T>>, //
can_for_each_nothrow<Func, Array, T>>;

template <typename Func, typename Array>
static constexpr bool for_each_is_nothrow = for_each_is_nothrow_one<Func, Array, table> //
&& for_each_is_nothrow_one<Func, Array, array> //
&& for_each_is_nothrow_one<Func, Array, std::string> //
&& for_each_is_nothrow_one<Func, Array, int64_t> //
&& for_each_is_nothrow_one<Func, Array, double> //
&& for_each_is_nothrow_one<Func, Array, bool> //
&& for_each_is_nothrow_one<Func, Array, date> //
&& for_each_is_nothrow_one<Func, Array, time> //
&& for_each_is_nothrow_one<Func, Array, date_time>;

// clang-format on
using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Array, table>,
for_each_is_nothrow_one<Func, Array, array>,
for_each_is_nothrow_one<Func, Array, std::string>,
for_each_is_nothrow_one<Func, Array, int64_t>,
for_each_is_nothrow_one<Func, Array, double>,
for_each_is_nothrow_one<Func, Array, bool>,
for_each_is_nothrow_one<Func, Array, date>,
for_each_is_nothrow_one<Func, Array, time>,
for_each_is_nothrow_one<Func, Array, date_time>>;

template <typename Func, typename Array>
static void do_for_each(Func&& visitor, Array&& arr) noexcept(for_each_is_nothrow<Func&&, Array&&>)
static void do_for_each(Func&& visitor, Array&& arr) //
noexcept(for_each_is_nothrow<Func&&, Array&&>::value)
{
static_assert(can_for_each_any<Func&&, Array&&>,
static_assert(can_for_each_any<Func&&, Array&&>::value,
"TOML array for_each visitors must be invocable for at least one of the toml::node "
"specializations:" TOML_SA_NODE_TYPE_LIST);

Expand All @@ -887,13 +912,46 @@ TOML_NAMESPACE_START
using node_ref = impl::copy_cvref<toml::node, Array&&>;
static_assert(std::is_reference_v<node_ref>);

#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN

#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
static_assert(impl::always_false<Func, Array, node_ref>, //
TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
#endif

static_cast<node_ref>(static_cast<Array&&>(arr)[i])
.visit(
[&]([[maybe_unused]] auto&& elem) //
noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
{
using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
static_assert(std::is_reference_v<elem_ref>);

// func(elem, i)
if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
{
static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
}

// func(i, elem)
else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
{
static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
}

// func(elem)
else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
{
static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
}
});

#else
const auto keep_going =
static_cast<node_ref>(static_cast<Array&&>(arr)[i])
.visit(
[&](auto&& elem)
#if !TOML_MSVC // MSVC thinks this is invalid syntax O_o
noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>)
#endif
[&]([[maybe_unused]] auto&& elem) //
noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
{
using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
static_assert(std::is_reference_v<elem_ref>);
Expand Down Expand Up @@ -959,6 +1017,7 @@ TOML_NAMESPACE_START

if (!keep_going)
return;
#endif
}
}

Expand Down Expand Up @@ -1026,31 +1085,35 @@ TOML_NAMESPACE_START
///
/// \see node::visit()
template <typename Func>
array& for_each(Func&& visitor) & noexcept(for_each_is_nothrow<Func&&, array&>)
array& for_each(Func&& visitor) & //
noexcept(for_each_is_nothrow<Func&&, array&>::value)
{
do_for_each(static_cast<Func&&>(visitor), *this);
return *this;
}

/// \brief Invokes a visitor on each element in the array (rvalue overload).
template <typename Func>
array&& for_each(Func&& visitor) && noexcept(for_each_is_nothrow<Func&&, array&&>)
array&& for_each(Func&& visitor) && //
noexcept(for_each_is_nothrow<Func&&, array&&>::value)
{
do_for_each(static_cast<Func&&>(visitor), static_cast<array&&>(*this));
return static_cast<array&&>(*this);
}

/// \brief Invokes a visitor on each element in the array (const lvalue overload).
template <typename Func>
const array& for_each(Func&& visitor) const& noexcept(for_each_is_nothrow<Func&&, const array&>)
const array& for_each(Func&& visitor) const& //
noexcept(for_each_is_nothrow<Func&&, const array&>::value)
{
do_for_each(static_cast<Func&&>(visitor), *this);
return *this;
}

/// \brief Invokes a visitor on each element in the array (const rvalue overload).
template <typename Func>
const array&& for_each(Func&& visitor) const&& noexcept(for_each_is_nothrow<Func&&, const array&&>)
const array&& for_each(Func&& visitor) const&& //
noexcept(for_each_is_nothrow<Func&&, const array&&>::value)
{
do_for_each(static_cast<Func&&>(visitor), static_cast<const array&&>(*this));
return static_cast<const array&&>(*this);
Expand Down
4 changes: 2 additions & 2 deletions include/toml++/impl/forward_declarations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,8 +465,8 @@ TOML_IMPL_NAMESPACE_START
using copy_cvref =
copy_ref<copy_ref<copy_cv<std::remove_reference_t<Dest>, std::remove_reference_t<Src>>, Dest>, Src>;

template <typename T>
inline constexpr bool dependent_false = false;
template <typename...>
inline constexpr bool always_false = false;

template <typename T, typename... U>
inline constexpr bool first_is_same = false;
Expand Down
8 changes: 4 additions & 4 deletions include/toml++/impl/make_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ TOML_IMPL_NAMESPACE_START
if constexpr (!is_losslessly_convertible_to_native<unwrapped_type>)
{
if constexpr (std::is_same_v<native_type, int64_t>)
static_assert(dependent_false<T>,
static_assert(always_false<T>,
"Integral value initializers must be losslessly convertible to int64_t");
else if constexpr (std::is_same_v<native_type, double>)
static_assert(dependent_false<T>,
static_assert(always_false<T>,
"Floating-point value initializers must be losslessly convertible to double");
else
static_assert(
dependent_false<T>,
always_false<T>,
"Value initializers must be losslessly convertible to one of the TOML value types");
}

Expand All @@ -65,7 +65,7 @@ TOML_IMPL_NAMESPACE_START
#if TOML_ENABLE_WINDOWS_COMPAT
out = new value_type{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
static_assert(always_false<T>, "Evaluated unreachable branch!");
#endif
}
else
Expand Down
4 changes: 2 additions & 2 deletions include/toml++/impl/node_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ TOML_NAMESPACE_START

#else

static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
static_assert(impl::always_false<T>, "Evaluated unreachable branch!");

#endif
}
Expand Down Expand Up @@ -656,7 +656,7 @@ TOML_NAMESPACE_START
#if TOML_ENABLE_WINDOWS_COMPAT
return lhs == impl::narrow(rhs);
#else
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
static_assert(impl::always_false<T>, "Evaluated unreachable branch!");
#endif
}
else
Expand Down
Loading

0 comments on commit d46cac7

Please sign in to comment.