From: Jacob Lifshay Date: Thu, 1 Jun 2017 06:06:54 +0000 (-0700) Subject: util::variant implemented X-Git-Tag: gsoc-2017~118 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5b8953f9b5d31426edf95e19902c5b0f9331ef1b;p=kazan.git util::variant implemented --- diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index a775745..2059497 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -21,8 +21,10 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) set(sources copy_cv_ref.cpp in_place.cpp + invoke.cpp is_referenceable.cpp is_swappable.cpp optional.cpp + variant.cpp void_t.cpp) add_library(util STATIC ${sources}) diff --git a/src/util/invoke.cpp b/src/util/invoke.cpp new file mode 100644 index 0000000..67bf132 --- /dev/null +++ b/src/util/invoke.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2017 Jacob Lifshay + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include "invoke.h" diff --git a/src/util/invoke.h b/src/util/invoke.h new file mode 100644 index 0000000..0a8f05c --- /dev/null +++ b/src/util/invoke.h @@ -0,0 +1,277 @@ +/* + * Copyright 2017 Jacob Lifshay + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef SOURCE_UTIL_INVOKE_H_ +#define SOURCE_UTIL_INVOKE_H_ + +#include +#include +#include +#include "void_t.h" + +namespace vulkan_cpu +{ +namespace util +{ +namespace detail +{ +template ::value>::type> +constexpr decltype(auto) invoke_helper(Fn &&fn, Args &&... args) noexcept( + noexcept(std::declval()(std::declval()...))) +{ + return std::forward(fn)(std::forward(args)...); +} + +template < + typename Fn, + typename T, + typename Arg1, + typename... Args, + typename = + typename std::enable_if::type>::value>::type> +constexpr decltype(auto) invoke_member_function_pointer( + Fn T::*fn, + Arg1 &&arg1, + Args &&... args) noexcept(noexcept((std::forward(arg1).*fn)(std::forward(args)...))) +{ + return (std::forward(arg1).*fn)(std::forward(args)...); +} + +template +struct invoke_is_reference_wrapper +{ + static constexpr bool value = false; +}; + +template +struct invoke_is_reference_wrapper> +{ + static constexpr bool value = true; +}; + +template < + typename Fn, + typename T, + typename Arg1, + typename... Args, + typename = int, + typename = typename std::enable_if::type>::value + && invoke_is_reference_wrapper< + typename std::decay::type>::value>::type> +constexpr decltype(auto) invoke_member_function_pointer( + Fn T::*fn, + Arg1 &&arg1, + Args &&... args) noexcept(noexcept((arg1.get().*fn)(std::forward(args)...))) +{ + return (arg1.get().*fn)(std::forward(args)...); +} + +template < + typename Fn, + typename T, + typename Arg1, + typename... Args, + typename = int, + typename = int, + typename = typename std::enable_if::type>::value + && !invoke_is_reference_wrapper< + typename std::decay::type>::value>::type> +constexpr decltype(auto) invoke_member_function_pointer( + Fn T::*fn, Arg1 &&arg1, Args &&... args) noexcept(noexcept(((*std::forward(arg1)) + .*fn)(std::forward(args)...))) +{ + return ((*std::forward(arg1)).*fn)(std::forward(args)...); +} + +template ::value>::type> +constexpr decltype(auto) invoke_helper(Fn fn, Args &&... args) noexcept( + noexcept(invoke_member_function_pointer(fn, std::forward(args)...))) +{ + return invoke_member_function_pointer(fn, std::forward(args)...); +} + +template < + typename Fn, + typename T, + typename Arg, + typename = + typename std::enable_if::type>::value>::type> +constexpr decltype(auto) invoke_member_object_pointer(Fn T::*fn, Arg &&arg) noexcept( + noexcept(std::forward(arg).*fn)) +{ + return std::forward(arg).*fn; +} + +template < + typename Fn, + typename T, + typename Arg, + typename = int, + typename = typename std::enable_if::type>::value + && invoke_is_reference_wrapper< + typename std::decay::type>::value>::type> +constexpr decltype(auto) invoke_member_object_pointer(Fn T::*fn, + Arg &&arg) noexcept(noexcept(arg.get().*fn)) +{ + return arg.get().*fn; +} + +template < + typename Fn, + typename T, + typename Arg, + typename = int, + typename = int, + typename = typename std::enable_if::type>::value + && !invoke_is_reference_wrapper< + typename std::decay::type>::value>::type> +constexpr decltype(auto) invoke_member_object_pointer(Fn T::*fn, Arg &&arg) noexcept( + noexcept((*std::forward(arg)).*fn)) +{ + return (*std::forward(arg)).*fn; +} + +template ::value>::type> +constexpr decltype(auto) invoke_helper(Fn fn, Arg &&arg) noexcept( + noexcept(invoke_member_object_pointer(fn, std::forward(arg)))) +{ + return invoke_member_object_pointer(fn, std::forward(arg)); +} + +template +struct invoke_result_helper +{ + static constexpr bool is_invokable = false; + static constexpr bool is_nothrow_invokable = false; + template + static constexpr bool is_invokable_r() noexcept + { + return false; + } + template + static constexpr bool is_nothrow_invokable_r() noexcept + { + return false; + } +}; + +template +struct invoke_result_helper(), std::declval()...))>, + Args...> +{ + typedef decltype(invoke_helper(std::declval(), std::declval()...)) type; + static constexpr bool is_invokable = true; + static constexpr bool is_nothrow_invokable = + noexcept(invoke_helper(std::declval(), std::declval()...)); + template + static constexpr bool is_invokable_r() noexcept + { + return std::is_void::value || std::is_convertible::value; + } + template + static constexpr bool is_nothrow_invokable_r_helper(...) noexcept + { + return false; + } + template (invoke_helper(std::declval(), + std::declval()...)))> + static constexpr bool is_nothrow_invokable_r_helper(int) noexcept + { + return is_invokable_r() && Is_Nothrow; + } + template + constexpr bool is_nothrow_invokable_r() noexcept + { + return is_nothrow_invokable_r_helper(0); + } +}; +} + +template +struct invoke_result : public detail::invoke_result_helper +{ +}; + +template +using invoke_result_t = typename invoke_result::type; + +template +constexpr invoke_result_t invoke(Fn &&fn, Args &&... args) noexcept( + noexcept(detail::invoke_helper(std::declval(), std::declval()...))) +{ + return detail::invoke_helper(std::forward(fn), std::forward(args)...); +} + +template +struct is_invocable + : public std::integral_constant::is_invokable> +{ +}; + +template +constexpr bool is_invocable_v = is_invocable::value; + +template +struct is_invocable_r + : public std::integral_constant::template is_invokable_r()> +{ +}; + +template +constexpr bool is_invocable_r_v = is_invocable_r::value; + +template +struct is_nothrow_invocable + : public std::integral_constant::is_nothrow_invokable> +{ +}; + +template +constexpr bool is_nothrow_invocable_v = is_nothrow_invocable::value; + +template +struct is_nothrow_invocable_r + : public std:: + integral_constant::template is_nothrow_invokable_r()> +{ +}; + +template +constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r::value; +} +} + +#endif /* SOURCE_UTIL_INVOKE_H_ */ diff --git a/src/util/variant.cpp b/src/util/variant.cpp new file mode 100644 index 0000000..5854282 --- /dev/null +++ b/src/util/variant.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2017 Jacob Lifshay + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include "variant.h" diff --git a/src/util/variant.h b/src/util/variant.h index 19ef314..f32aa2a 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -34,6 +34,7 @@ #include "void_t.h" #include "copy_cv_ref.h" #include "is_swappable.h" +#include "invoke.h" namespace vulkan_cpu { @@ -41,6 +42,7 @@ namespace util { class bad_variant_access : public std::exception { +public: bad_variant_access() noexcept = default; virtual const char *what() const noexcept override { @@ -124,7 +126,7 @@ struct variant_alternative }; template -struct variant_alternative +struct variant_alternative { typedef const typename variant_alternative::type type; }; @@ -170,11 +172,69 @@ struct variant_hypothetical_overload_set }; template <> -struct variant_hypothetical_overload_set +struct variant_hypothetical_overload_set<> { static void fn(); // not implemented }; +template +struct variant_is_equals_comparable +{ +private: + static std::false_type fn(...); + template (std::declval() + == std::declval()))> + static std::true_type fn(const T2 &); + +public: + static constexpr bool value = decltype(fn(std::declval()))::value; +}; + +template +struct variant_is_less_comparable +{ +private: + static std::false_type fn(...); + template (std::declval() + < std::declval()))> + static std::true_type fn(const T2 &); + +public: + static constexpr bool value = decltype(fn(std::declval()))::value; +}; + +template +struct variant_is_nothrow_equals_comparable +{ +private: + static std::false_type fn(...); + template + static std::integral_constant(std::declval() + == std::declval()))> + fn(const T2 &); + +public: + static constexpr bool value = decltype(fn(std::declval()))::value; +}; + +template +struct variant_is_nothrow_less_comparable +{ +private: + static std::false_type fn(...); + template + static std::integral_constant(std::declval() + < std::declval()))> + fn(const T2 &); + +public: + static constexpr bool value = decltype(fn(std::declval()))::value; +}; + template union variant_values { @@ -190,6 +250,10 @@ union variant_values static constexpr bool is_trivially_destructible = true; static constexpr bool is_swappable = true; static constexpr bool is_nothrow_swappable = true; + static constexpr bool is_equals_comparable = true; + static constexpr bool is_less_comparable = true; + static constexpr bool is_nothrow_equals_comparable = true; + static constexpr bool is_nothrow_less_comparable = true; variant_values() = delete; template constexpr variant_values(in_place_index_t) noexcept : value() @@ -218,6 +282,14 @@ union variant_values void swap(variant_values &rt, std::size_t index) noexcept { } + bool is_equal(const variant_values &rt, std::size_t index) const noexcept + { + return true; + } + bool is_less(const variant_values &rt, std::size_t index) const noexcept + { + return false; + } }; template @@ -227,6 +299,9 @@ union variant_values static_assert(!std::is_void::value, "invalid variant member type"); static_assert(!std::is_reference::value, "invalid variant member type"); static_assert(!std::is_array::value, "invalid variant member type"); + static_assert(!std::is_const::value, "invalid variant member type"); + static_assert(!std::is_volatile::value, "invalid variant member type"); + static_assert(std::is_object::value, "invalid variant member type"); T current_value; variant_values other_values; static constexpr bool is_copy_constructible = @@ -254,13 +329,21 @@ union variant_values static constexpr bool is_trivially_destructible = std::is_trivially_destructible::value && variant_values::is_trivially_destructible; - static constexpr bool is_swappable = - is_swappable_v && std::is_move_constructible && variant_values:: - is_swappable; + static constexpr bool is_swappable = is_swappable_v && std::is_move_constructible::value + && variant_values::is_swappable; static constexpr bool is_nothrow_swappable = - is_nothrow_swappable_v && std:: - is_nothrow_move_constructible && variant_values:: - is_nothrow_swappable; + is_nothrow_swappable_v && std::is_nothrow_move_constructible::value + && variant_values::is_nothrow_swappable; + static constexpr bool is_equals_comparable = + variant_is_equals_comparable::value && variant_values::is_equals_comparable; + static constexpr bool is_less_comparable = + variant_is_less_comparable::value && variant_values::is_less_comparable; + static constexpr bool is_nothrow_equals_comparable = + variant_is_nothrow_equals_comparable::value + && variant_values::is_nothrow_equals_comparable; + static constexpr bool is_nothrow_less_comparable = + variant_is_nothrow_less_comparable::value + && variant_values::is_nothrow_less_comparable; template ::value>::type> constexpr variant_values() noexcept(std::is_nothrow_default_constructible::value) @@ -304,7 +387,7 @@ union variant_values template static constexpr std::size_t index_from_type() noexcept { - std::size_t next = variant_values::index_from_type(); + std::size_t next = variant_values::template index_from_type(); if(std::is_same::value && next == variant_npos) return 0; if(next == variant_npos) @@ -357,6 +440,20 @@ union variant_values else other_values.swap(rt.other_values, index - 1); } + bool is_equal(const variant_values &rt, std::size_t index) const + noexcept(is_nothrow_equals_comparable) + { + if(index == 0) + return static_cast(current_value == rt.current_value); + return other_values.is_equal(rt.other_values, index - 1); + } + bool is_less(const variant_values &rt, std::size_t index) const + noexcept(is_nothrow_less_comparable) + { + if(index == 0) + return static_cast(current_value < rt.current_value); + return other_values.is_equal(rt.other_values, index - 1); + } }; template @@ -423,7 +520,7 @@ struct variant_get<0, T, Types...> { \ typedef Return_Type (*Dispatch_Function)( \ Fn && fn, Const variant_values & values, Args && ... args); \ - static const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \ + const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \ static_cast( \ [](Fn &&fn, Const variant_values &values, Args &&... args) \ -> Return_Type \ @@ -472,7 +569,7 @@ struct variant_get<0, T, Types...> { \ typedef Return_Type (*Dispatch_Function)( \ Fn && fn, Const variant_values & values, Args && ... args); \ - static const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \ + const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \ static_cast( \ [](Fn &&fn, Const variant_values &values, Args &&... args) \ -> Return_Type \ @@ -517,7 +614,7 @@ template ::fn(std::declval()))::type, - std::size_t Index = variant_values::index_from_type(), + std::size_t Index = variant_values::template index_from_type(), typename = typename std::enable_if<(Index < sizeof...(Types))>::type> constexpr std::size_t variant_conversion_deduce_index() noexcept { @@ -526,7 +623,7 @@ constexpr std::size_t variant_conversion_deduce_index() noexcept template using variant_conversion_deduce_type = - variant_alternative_t(), Types...>; + variant_alternative_t(), variant>; template struct variant_index_type @@ -630,6 +727,22 @@ struct variant_is_in_place_type> { static constexpr bool value = true; }; + +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, variant &v, Args &&... args); + +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, const variant &v, Args &&... args); + +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, variant &&v, Args &&... args); + +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, const variant &&v, Args &&... args); } template @@ -660,7 +773,7 @@ public: typename std::enable_if::is_copy_constructible>::type> variant(const variant &rt) noexcept( detail::variant_values::is_nothrow_copy_constructible) - : base(variant_npos, in_place_index()) + : base(variant_npos, in_place_index) { values.copy_construct(rt.values, rt.index_value.get()); index_value = rt.index_value; @@ -669,7 +782,7 @@ public: typename = typename std::enable_if::is_move_constructible>::type> variant(variant &&rt) noexcept(detail::variant_values::is_nothrow_move_constructible) - : base(variant_npos, in_place_index()) + : base(variant_npos, in_place_index) { values.move_construct(std::move(rt.values), rt.index_value.get()); index_value = rt.index_value; @@ -690,7 +803,7 @@ public: } template ::index_from_type(), + std::size_t Index = detail::variant_values::template index_from_type(), typename = typename std::enable_if<(Index < sizeof...(Types)) && std::is_constructible::value>::type> constexpr explicit variant(in_place_type_t, Args &&... args) noexcept( @@ -702,7 +815,7 @@ public: typename T, typename U, typename... Args, - std::size_t Index = detail::variant_values::index_from_type(), + std::size_t Index = detail::variant_values::template index_from_type(), typename = typename std:: enable_if<(Index < sizeof...(Types)) && std::is_constructible, Args...>::value>::type> @@ -812,7 +925,7 @@ public: } template ::index_from_type(), + std::size_t Index = detail::variant_values::template index_from_type(), typename = typename std::enable_if<(Index < sizeof...(Types)) && std::is_constructible::value>::type> void emplace(Args &&... args) @@ -823,7 +936,7 @@ public: typename T, typename U, typename... Args, - std::size_t Index = detail::variant_values::index_from_type(), + std::size_t Index = detail::variant_values::template index_from_type(), typename = typename std:: enable_if<(Index < sizeof...(Types)) && std::is_constructible, Args...>::value>::type> @@ -886,8 +999,279 @@ public: *this = std::move(temp); } } + template + friend constexpr bool holds_alternative(const variant &v) noexcept; + template + friend constexpr variant_alternative_t> &get(variant &v); + template + friend constexpr const variant_alternative_t> &get( + const variant &v); + template + friend constexpr + typename std::enable_if::is_equals_comparable, bool>::type + operator==(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_equals_comparable); + template + friend constexpr + typename std::enable_if::is_less_comparable, bool>::type + operator<(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_less_comparable); + template + friend typename std::common_type()(std::declval()))...>::type + detail::variant_dispatch(Fn &&fn, variant &v, Args &&... args); + template + friend typename std::common_type()(std::declval()))...>::type + detail::variant_dispatch(Fn &&fn, const variant &v, Args &&... args); + template + friend + typename std::common_type()(std::declval()))...>::type + detail::variant_dispatch(Fn &&fn, variant &&v, Args &&... args); + template + friend typename std::common_type()(std::declval()))...>::type + detail::variant_dispatch(Fn &&fn, const variant &&v, Args &&... args); }; -#error finish + +template +constexpr bool holds_alternative(const variant &v) noexcept +{ + constexpr std::size_t index = detail::variant_values::template index_from_type(); + static_assert(index != variant_npos, ""); + return v.index_value.get() == index; +} + +template +constexpr variant_alternative_t> &get(variant &v) +{ + static_assert(Index < sizeof...(Types), ""); + if(v.index_value.get() == Index) + return detail::variant_get::get(v.values); + throw bad_variant_access(); +} + +template +constexpr const variant_alternative_t> &get(const variant &v) +{ + static_assert(Index < sizeof...(Types), ""); + if(v.index_value.get() == Index) + return detail::variant_get::get(v.values); + throw bad_variant_access(); +} + +template +constexpr const variant_alternative_t> &&get(const variant &&v) +{ + return std::move(get(v)); +} + +template +constexpr variant_alternative_t> &&get(variant &&v) +{ + return std::move(get(v)); +} + +template +constexpr const T &get(const variant &v) +{ + return get::template index_from_type()>(v); +} + +template +constexpr T &get(variant &v) +{ + return get::template index_from_type()>(v); +} + +template +constexpr const T &&get(const variant &&v) +{ + return get::template index_from_type()>(std::move(v)); +} + +template +constexpr T &&get(variant &&v) +{ + return get::template index_from_type()>(std::move(v)); +} + +template +constexpr const variant_alternative_t> *get_if( + const variant *v) noexcept +{ + static_assert(Index < sizeof...(Types), ""); + if(!v || v->index() != Index) + return nullptr; + return std::addressof(get(*v)); +} + +template +constexpr variant_alternative_t> *get_if(variant *v) noexcept +{ + static_assert(Index < sizeof...(Types), ""); + if(!v || v->index() != Index) + return nullptr; + return std::addressof(get(*v)); +} + +template +constexpr const T *get_if(const variant *v) noexcept +{ + return get_if::template index_from_type()>(v); +} + +template +constexpr T *get_if(variant *v) noexcept +{ + return get_if::template index_from_type()>(v); +} + +template +constexpr + typename std::enable_if::is_equals_comparable, bool>::type + operator==(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_equals_comparable) +{ + return l.index_value.get() == r.index_value.get() + && l.values.is_equal(r.values, l.index_value.get()); +} + +template +constexpr + typename std::enable_if::is_equals_comparable, bool>::type + operator!=(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_equals_comparable) +{ + return !operator==(l, r); +} + +template +constexpr typename std::enable_if::is_less_comparable, bool>::type + operator<(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_less_comparable) +{ + if(l.index_value.get() != r.index_value.get()) + return l.index_value.get() < r.index_value.get(); + return l.values.is_less(r.values, l.index_value.get()); +} + +template +constexpr typename std::enable_if::is_less_comparable, bool>::type + operator>(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_less_comparable) +{ + return operator<(r, l); +} + +template +constexpr typename std::enable_if::is_less_comparable, bool>::type + operator>=(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_less_comparable) +{ + return !operator<(l, r); +} + +template +constexpr typename std::enable_if::is_less_comparable, bool>::type + operator<=(const variant &l, const variant &r) noexcept( + detail::variant_values::is_nothrow_less_comparable) +{ + return !operator<(r, l); +} + +namespace detail +{ +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, variant &v, Args &&... args) +{ + return variant_dispatch( + std::forward(fn), v.values, v.index_value.get(), std::forward(args)...); +} + +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, const variant &v, Args &&... args) +{ + return variant_dispatch( + std::forward(fn), v.values, v.index_value.get(), std::forward(args)...); +} + +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, variant &&v, Args &&... args) +{ + return variant_dispatch(std::forward(fn), + std::move(v.values), + v.index_value.get(), + std::forward(args)...); +} + +template +typename std::common_type()(std::declval()))...>::type + variant_dispatch(Fn &&fn, const variant &&v, Args &&... args) +{ + return variant_dispatch(std::forward(fn), + std::move(v.values), + v.index_value.get(), + std::forward(args)...); +} + +template +decltype(variant_dispatch(std::declval(), std::declval &>())) variant_visit( + Fn &&fn, variant &v) +{ + return variant_dispatch(std::forward(fn), v); +} + +template +decltype(variant_dispatch(std::declval(), std::declval &>())) + variant_visit(Fn &&fn, const variant &v) +{ + return variant_dispatch(std::forward(fn), v); +} + +template +decltype(variant_dispatch(std::declval(), std::declval &&>())) variant_visit( + Fn &&fn, variant &&v) +{ + return variant_dispatch(std::forward(fn), std::move(v)); +} + +template +decltype(variant_dispatch(std::declval(), std::declval &&>())) + variant_visit(Fn &&fn, const variant &&v) +{ + return variant_dispatch(std::forward(fn), std::move(v)); +} + +template +auto variant_visit(Fn &&fn, + const variant &&v, + Variant2 &&variant2, + Variants &&... variants) +{ + return variant_dispatch( + [&](auto &&value) + { + return variant_visit( + [&](auto &&... args) + { + return std::forward(fn)(std::forward(value), + std::forward(args)...); + }, + std::forward(variant2), + std::forward(variants)...); + }, + std::move(v)); +} +} + +template +auto visit(Fn &&fn, Variants &&... variants) +{ + return detail::variant_visit(std::forward(fn), std::forward(variants)...); +} } } @@ -902,6 +1286,23 @@ struct hash } }; +template +struct hash> +{ + constexpr std::size_t operator()(const vulkan_cpu::util::variant &v) const + { + if(v.valueless_by_exception()) + return 10285473UL; + return v.index() * 1414729UL + + vulkan_cpu::util::visit( + [](const auto &v) -> std::size_t + { + return std::hash::type>()(v); + }, + v); + } +}; + template ::is_swappable>::type>