diff --git a/include/dice/template-library/type_list.hpp b/include/dice/template-library/type_list.hpp index d1799b7..cf843cc 100644 --- a/include/dice/template-library/type_list.hpp +++ b/include/dice/template-library/type_list.hpp @@ -293,6 +293,22 @@ namespace dice::template_library::type_list { using filter_t = typename filter::type; + /** + * Flatten a type list of type lists of types into a type list of types. + * @tparam TL type list of type lists + */ + template + struct flatten; + + template + struct flatten> { + using type = concat_t; + }; + + template + using flatten_t = typename flatten::type; + + namespace detail_generate { template struct generate_impl; @@ -506,6 +522,25 @@ namespace dice::template_library::type_list { using integer_sequence_to_type_list_t = typename integer_sequence_to_type_list::type; + /** + * Convert a tuple-like thing into a type list of its component types. + */ + template + struct tuple_to_type_list; + + template + requires requires { + { std::tuple_size_v } -> std::convertible_to; + } + struct tuple_to_type_list { + using type = decltype([](std::index_sequence) { + return type_list...>{}; + }(std::make_index_sequence>{})); + }; + + template + using tuple_to_type_list_t = typename tuple_to_type_list::type; + /** * A marker type to indicate a failed operation * when using opt diff --git a/include/dice/template-library/variant2.hpp b/include/dice/template-library/variant2.hpp index 4cadd35..9f672f8 100644 --- a/include/dice/template-library/variant2.hpp +++ b/include/dice/template-library/variant2.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -720,7 +721,7 @@ namespace dice::template_library { rhs = std::move(tmp); } - constexpr bool operator==(variant2 const &other) const noexcept { + constexpr bool operator==(variant2 const &other) const noexcept requires (std::equality_comparable && std::equality_comparable) { if (discriminant_ != other.discriminant_) { return false; } @@ -742,7 +743,7 @@ namespace dice::template_library { } } - constexpr auto operator<=>(variant2 const &other) const noexcept { + constexpr auto operator<=>(variant2 const &other) const noexcept requires (std::three_way_comparable && std::three_way_comparable) { using ret_type = std::common_comparison_category_t, std::compare_three_way_result_t>; if (discriminant_ != other.discriminant_) { @@ -903,4 +904,23 @@ namespace dice::template_library { } // namespace dice::template_library +template requires (std::formattable && std::formattable) +struct std::formatter<::dice::template_library::variant2> { + template + constexpr auto parse(Ctx &ctx) { + return ctx.begin(); + } + + template + auto format(::dice::template_library::variant2 const &var, Ctx &ctx) const { + // formatting the same way libfmt does + if (var.valueless_by_exception()) { + return std::format_to(ctx.out(), "variant(valueless by exception)"); + } + return ::dice::template_library::visit([&ctx](auto const &value) { + return std::format_to(ctx.out(), "variant({})", value); + }, var); + } +}; + #endif // DICE_TEMPLATELIBRARY_VARIANT2_HPP diff --git a/tests/tests_type_list.cpp b/tests/tests_type_list.cpp index ee48ef3..0942084 100644 --- a/tests/tests_type_list.cpp +++ b/tests/tests_type_list.cpp @@ -159,6 +159,13 @@ TEST_SUITE("type_list") { static_assert(std::is_same_v, tl::type_list>); } + TEST_CASE("flatten") { + static_assert(std::is_same_v, empty_t>); + static_assert(std::is_same_v>, empty_t>); + static_assert(std::is_same_v, empty_t, tl::type_list>>, tl::type_list>); + static_assert(std::is_same_v>>>, tl::type_list>>); + } + TEST_CASE("generate") { static_assert(std::is_same_v, empty_t>); @@ -302,6 +309,16 @@ TEST_SUITE("type_list") { static_assert(std::is_same_v, expected_iseq_tl>); } + TEST_CASE("tuple_to_type_list") { + using empty_tuple = std::tuple<>; + using pair = std::pair; + using tuple = std::tuple; + + static_assert(std::is_same_v, empty_t>); + static_assert(std::is_same_v, tl::type_list>); + static_assert(std::is_same_v, tl::type_list>); + } + TEST_CASE("for_each") { using t1 = tl::type_list; diff --git a/tests/tests_variant2.cpp b/tests/tests_variant2.cpp index c4476bc..d478768 100644 --- a/tests/tests_variant2.cpp +++ b/tests/tests_variant2.cpp @@ -7,6 +7,47 @@ using namespace std::string_literals; +struct make_valueless { + make_valueless() { + throw std::runtime_error{"aaa"}; + } + + explicit make_valueless(std::nothrow_t) noexcept {} + + make_valueless(make_valueless const &) { + throw std::runtime_error{"aaa"}; + } + + make_valueless(make_valueless &&) { + throw std::runtime_error{"aaa"}; + } + + make_valueless &operator=(make_valueless const &) { + throw std::runtime_error{"aaa"}; + } + + make_valueless &operator=(make_valueless &&) { + throw std::runtime_error{"aaa"}; + } + + ~make_valueless() noexcept = default; + + auto operator<=>(make_valueless const &) const noexcept = default; +}; + +template<> +struct std::formatter { + template + constexpr auto parse(Ctx &parse_ctx) { + return parse_ctx.begin(); + } + + template + auto format(make_valueless const &, Ctx &format_ctx) const { + return std::format_to(format_ctx.out(), "make_valueluess"); + } +}; + TEST_SUITE("variant2") { using namespace dice::template_library; @@ -29,34 +70,6 @@ TEST_SUITE("variant2") { && std::is_const_v> == std::is_const_v>; - struct make_valueless { - make_valueless() { - throw std::runtime_error{"aaa"}; - } - - explicit make_valueless(std::nothrow_t) noexcept {} - - make_valueless(make_valueless const &) { - throw std::runtime_error{"aaa"}; - } - - make_valueless(make_valueless &&) { - throw std::runtime_error{"aaa"}; - } - - make_valueless &operator=(make_valueless const &) { - throw std::runtime_error{"aaa"}; - } - - make_valueless &operator=(make_valueless &&) { - throw std::runtime_error{"aaa"}; - } - - ~make_valueless() noexcept = default; - - auto operator<=>(make_valueless const &) const noexcept = default; - }; - template void check_acessors(Variant &&x, T const &expected_val) { static constexpr size_t index = variant_index>::value; @@ -289,4 +302,16 @@ TEST_SUITE("variant2") { static_assert(!std::is_trivially_destructible_v); static_assert(!std::is_trivially_copyable_v); } + + TEST_CASE("formatting") { + CHECK(std::format("{}", variant2{42}) == "variant(42)"); + CHECK(std::format("{}", variant2{1.5}) == "variant(1.5)"); + + variant2 valueless{}; + try { + valueless = make_valueless{std::nothrow}; + } catch (...) { + } + CHECK(std::format("{}", valueless) == "variant(valueless by exception)"); + } }