// This file is a part of toml++ and is subject to the the terms of the MIT license. // Copyright (c) Mark Gillard // See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT #include "tests.hpp" TOML_DISABLE_SPAM_WARNINGS; TEST_CASE("array::for_each") { toml::array arr{ 0, 1, 2, 3.0, "four", "five", 6 }; // check lvalue propagates correctly static_cast(arr).for_each( [](auto&& elem, size_t) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](size_t, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); // check rvalue propagates correctly static_cast(arr).for_each( [](auto&& elem, size_t) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](size_t, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); // check const lvalue propagates correctly static_cast(arr).for_each( [](auto&& elem, size_t) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](size_t, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); // check const rvalue propagates correctly static_cast(arr).for_each( [](auto&& elem, size_t) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](size_t, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(arr).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); // check noexcept - func(elem, i) { static constexpr auto throwing_visitor = [](auto&&, size_t) noexcept(false) {}; static constexpr auto non_throwing_visitor = [](auto&&, size_t) noexcept(true) {}; static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); } // check noexcept - func(i, elem) { static constexpr auto throwing_visitor = [](size_t, auto&&) noexcept(false) {}; static constexpr auto non_throwing_visitor = [](size_t, auto&&) noexcept(true) {}; static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); } // check noexcept - func(elem) { static constexpr auto throwing_visitor = [](auto&&) noexcept(false) {}; static constexpr auto non_throwing_visitor = [](auto&&) noexcept(true) {}; static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(arr).for_each(throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(arr).for_each(non_throwing_visitor))); } // check that the iteration actually does what it says on the box { toml::array arr2; arr.for_each([&](const auto& val) { arr2.push_back(val); }); CHECK(arr == arr2); } // check that visitation works for a specific type { toml::array arr2; arr.for_each([&](const toml::value& val) { arr2.push_back(val); }); CHECK(arr2 == toml::array{ 0, 1, 2, 6 }); } #if !TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN // check that early-stopping works { toml::array arr2; arr.for_each( [&](const auto& val) { if constexpr (!toml::is_number) return false; else { arr2.push_back(val); return true; } }); CHECK(arr2 == toml::array{ 0, 1, 2, 3.0 }); } #endif } TEST_CASE("table::for_each") { table tbl{ { "zero", 0 }, // { "one", 1 }, // { "two", 2 }, // { "three", 3.0 }, // { "four", "four" }, // { "five", "five" }, // { "six", 6 } }; // check lvalue propagates correctly static_cast(tbl).for_each( [](const toml::key&, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(tbl).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); // check rvalue propagates correctly static_cast(tbl).for_each( [](const toml::key&, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(tbl).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(!std::is_const_v); static_assert(!std::is_volatile_v); }); // check const lvalue propagates correctly static_cast(tbl).for_each( [](const toml::key&, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(tbl).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_lvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); // check const rvalue propagates correctly static_cast(tbl).for_each( [](const toml::key&, auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); static_cast(tbl).for_each( [](auto&& elem) noexcept { using elem_ref_type = decltype(elem); static_assert(std::is_rvalue_reference_v); using elem_type = std::remove_reference_t; static_assert(std::is_const_v); static_assert(!std::is_volatile_v); }); // check noexcept - func(key, value) { static constexpr auto throwing_visitor = [](const toml::key&, auto&&) noexcept(false) {}; static constexpr auto non_throwing_visitor = [](const toml::key&, auto&&) noexcept(true) {}; static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); } // check noexcept - func(value) { static constexpr auto throwing_visitor = [](auto&&) noexcept(false) {}; static constexpr auto non_throwing_visitor = [](auto&&) noexcept(true) {}; static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(!noexcept(static_cast(tbl).for_each(throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); static_assert(noexcept(static_cast(tbl).for_each(non_throwing_visitor))); } // check that the iteration actually does what it says on the box { toml::table tbl2; tbl.for_each([&](auto&& key, auto&& val) { tbl2.insert_or_assign(key, val); }); CHECK(tbl == tbl2); } // check that visitation works for a specific type { toml::table tbl2; tbl.for_each([&](auto&& key, const toml::value& val) { tbl2.insert_or_assign(key, val); }); CHECK(tbl2 == table{ { "zero", 0 }, // { "one", 1 }, // { "two", 2 }, // { "six", 6 } }); } #if !TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN // check that early-stopping works { toml::table tbl2; size_t added{}; tbl.for_each( [&](auto&& key, const auto& val) { tbl2.insert_or_assign(key, val); added++; return added < 3u; }); CHECK(tbl2.size() == 3u); } #endif }