--- /dev/null
+/*
+ * 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 <type_traits>
+#include <utility>
+#include <functional>
+#include "void_t.h"
+
+namespace vulkan_cpu
+{
+namespace util
+{
+namespace detail
+{
+template <typename Fn,
+ typename... Args,
+ typename = typename std::enable_if<!std::is_member_pointer<Fn>::value>::type>
+constexpr decltype(auto) invoke_helper(Fn &&fn, Args &&... args) noexcept(
+ noexcept(std::declval<Fn>()(std::declval<Args>()...)))
+{
+ return std::forward<Fn>(fn)(std::forward<Args>(args)...);
+}
+
+template <
+ typename Fn,
+ typename T,
+ typename Arg1,
+ typename... Args,
+ typename =
+ typename std::enable_if<std::is_base_of<T, typename std::decay<Arg1>::type>::value>::type>
+constexpr decltype(auto) invoke_member_function_pointer(
+ Fn T::*fn,
+ Arg1 &&arg1,
+ Args &&... args) noexcept(noexcept((std::forward<Arg1>(arg1).*fn)(std::forward<Args>(args)...)))
+{
+ return (std::forward<Arg1>(arg1).*fn)(std::forward<Args>(args)...);
+}
+
+template <typename T>
+struct invoke_is_reference_wrapper
+{
+ static constexpr bool value = false;
+};
+
+template <typename T>
+struct invoke_is_reference_wrapper<std::reference_wrapper<T>>
+{
+ static constexpr bool value = true;
+};
+
+template <
+ typename Fn,
+ typename T,
+ typename Arg1,
+ typename... Args,
+ typename = int,
+ typename = typename std::enable_if<!std::is_base_of<T, typename std::decay<Arg1>::type>::value
+ && invoke_is_reference_wrapper<
+ typename std::decay<Arg1>::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>(args)...)))
+{
+ return (arg1.get().*fn)(std::forward<Args>(args)...);
+}
+
+template <
+ typename Fn,
+ typename T,
+ typename Arg1,
+ typename... Args,
+ typename = int,
+ typename = int,
+ typename = typename std::enable_if<!std::is_base_of<T, typename std::decay<Arg1>::type>::value
+ && !invoke_is_reference_wrapper<
+ typename std::decay<Arg1>::type>::value>::type>
+constexpr decltype(auto) invoke_member_function_pointer(
+ Fn T::*fn, Arg1 &&arg1, Args &&... args) noexcept(noexcept(((*std::forward<Arg1>(arg1))
+ .*fn)(std::forward<Args>(args)...)))
+{
+ return ((*std::forward<Arg1>(arg1)).*fn)(std::forward<Args>(args)...);
+}
+
+template <typename Fn,
+ typename Arg1,
+ typename... Args,
+ typename = typename std::enable_if<std::is_member_function_pointer<Fn>::value>::type>
+constexpr decltype(auto) invoke_helper(Fn fn, Args &&... args) noexcept(
+ noexcept(invoke_member_function_pointer(fn, std::forward<Args>(args)...)))
+{
+ return invoke_member_function_pointer(fn, std::forward<Args>(args)...);
+}
+
+template <
+ typename Fn,
+ typename T,
+ typename Arg,
+ typename =
+ typename std::enable_if<std::is_base_of<T, typename std::decay<Arg>::type>::value>::type>
+constexpr decltype(auto) invoke_member_object_pointer(Fn T::*fn, Arg &&arg) noexcept(
+ noexcept(std::forward<Arg>(arg).*fn))
+{
+ return std::forward<Arg>(arg).*fn;
+}
+
+template <
+ typename Fn,
+ typename T,
+ typename Arg,
+ typename = int,
+ typename = typename std::enable_if<!std::is_base_of<T, typename std::decay<Arg>::type>::value
+ && invoke_is_reference_wrapper<
+ typename std::decay<Arg>::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<!std::is_base_of<T, typename std::decay<Arg>::type>::value
+ && !invoke_is_reference_wrapper<
+ typename std::decay<Arg>::type>::value>::type>
+constexpr decltype(auto) invoke_member_object_pointer(Fn T::*fn, Arg &&arg) noexcept(
+ noexcept((*std::forward<Arg>(arg)).*fn))
+{
+ return (*std::forward<Arg>(arg)).*fn;
+}
+
+template <typename Fn,
+ typename Arg,
+ typename = typename std::enable_if<std::is_member_object_pointer<Fn>::value>::type>
+constexpr decltype(auto) invoke_helper(Fn fn, Arg &&arg) noexcept(
+ noexcept(invoke_member_object_pointer(fn, std::forward<Arg>(arg))))
+{
+ return invoke_member_object_pointer(fn, std::forward<Arg>(arg));
+}
+
+template <typename Fn, typename = void, typename... Args>
+struct invoke_result_helper
+{
+ static constexpr bool is_invokable = false;
+ static constexpr bool is_nothrow_invokable = false;
+ template <typename R>
+ static constexpr bool is_invokable_r() noexcept
+ {
+ return false;
+ }
+ template <typename R>
+ static constexpr bool is_nothrow_invokable_r() noexcept
+ {
+ return false;
+ }
+};
+
+template <typename Fn, typename... Args>
+struct invoke_result_helper<Fn,
+ void_t<decltype(
+ invoke_helper(std::declval<Fn>(), std::declval<Args>()...))>,
+ Args...>
+{
+ typedef decltype(invoke_helper(std::declval<Fn>(), std::declval<Args>()...)) type;
+ static constexpr bool is_invokable = true;
+ static constexpr bool is_nothrow_invokable =
+ noexcept(invoke_helper(std::declval<Fn>(), std::declval<Args>()...));
+ template <typename R>
+ static constexpr bool is_invokable_r() noexcept
+ {
+ return std::is_void<R>::value || std::is_convertible<type, R>::value;
+ }
+ template <typename R>
+ static constexpr bool is_nothrow_invokable_r_helper(...) noexcept
+ {
+ return false;
+ }
+ template <typename R,
+ bool Is_Nothrow = noexcept(static_cast<R>(invoke_helper(std::declval<Fn>(),
+ std::declval<Args>()...)))>
+ static constexpr bool is_nothrow_invokable_r_helper(int) noexcept
+ {
+ return is_invokable_r<R>() && Is_Nothrow;
+ }
+ template <typename R>
+ constexpr bool is_nothrow_invokable_r() noexcept
+ {
+ return is_nothrow_invokable_r_helper<R>(0);
+ }
+};
+}
+
+template <typename Fn, typename... Args>
+struct invoke_result : public detail::invoke_result_helper<Fn, void, Args...>
+{
+};
+
+template <typename Fn, typename... Args>
+using invoke_result_t = typename invoke_result<Fn, Args...>::type;
+
+template <typename Fn, typename... Args>
+constexpr invoke_result_t<Fn, Args...> invoke(Fn &&fn, Args &&... args) noexcept(
+ noexcept(detail::invoke_helper(std::declval<Fn>(), std::declval<Args>()...)))
+{
+ return detail::invoke_helper(std::forward<Fn>(fn), std::forward<Args>(args)...);
+}
+
+template <typename Fn, typename... Args>
+struct is_invocable
+ : public std::integral_constant<bool, detail::invoke_result_helper<Fn, Args...>::is_invokable>
+{
+};
+
+template <typename Fn, typename... Args>
+constexpr bool is_invocable_v = is_invocable<Fn, Args...>::value;
+
+template <typename R, typename Fn, typename... Args>
+struct is_invocable_r
+ : public std::integral_constant<bool,
+ detail::invoke_result_helper<Fn, Args...>::template is_invokable_r<R>()>
+{
+};
+
+template <typename R, typename Fn, typename... Args>
+constexpr bool is_invocable_r_v = is_invocable_r<R, Fn, Args...>::value;
+
+template <typename Fn, typename... Args>
+struct is_nothrow_invocable
+ : public std::integral_constant<bool,
+ detail::invoke_result_helper<Fn, Args...>::is_nothrow_invokable>
+{
+};
+
+template <typename Fn, typename... Args>
+constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<Fn, Args...>::value;
+
+template <typename R, typename Fn, typename... Args>
+struct is_nothrow_invocable_r
+ : public std::
+ integral_constant<bool,
+ detail::invoke_result_helper<Fn, Args...>::template is_nothrow_invokable_r<R>()>
+{
+};
+
+template <typename R, typename Fn, typename... Args>
+constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<R, Fn, Args...>::value;
+}
+}
+
+#endif /* SOURCE_UTIL_INVOKE_H_ */
#include "void_t.h"
#include "copy_cv_ref.h"
#include "is_swappable.h"
+#include "invoke.h"
namespace vulkan_cpu
{
{
class bad_variant_access : public std::exception
{
+public:
bad_variant_access() noexcept = default;
virtual const char *what() const noexcept override
{
};
template <std::size_t Index, typename T>
-struct variant_alternative<Index, const T>
+struct variant_alternative<Index, volatile T>
{
typedef const typename variant_alternative<Index, T>::type type;
};
};
template <>
-struct variant_hypothetical_overload_set
+struct variant_hypothetical_overload_set<>
{
static void fn(); // not implemented
};
+template <typename T>
+struct variant_is_equals_comparable
+{
+private:
+ static std::false_type fn(...);
+ template <typename T2,
+ typename = decltype(static_cast<bool>(std::declval<const T2 &>()
+ == std::declval<const T2 &>()))>
+ static std::true_type fn(const T2 &);
+
+public:
+ static constexpr bool value = decltype(fn(std::declval<const T &>()))::value;
+};
+
+template <typename T>
+struct variant_is_less_comparable
+{
+private:
+ static std::false_type fn(...);
+ template <typename T2,
+ typename = decltype(static_cast<bool>(std::declval<const T2 &>()
+ < std::declval<const T2 &>()))>
+ static std::true_type fn(const T2 &);
+
+public:
+ static constexpr bool value = decltype(fn(std::declval<const T &>()))::value;
+};
+
+template <typename T>
+struct variant_is_nothrow_equals_comparable
+{
+private:
+ static std::false_type fn(...);
+ template <typename T2>
+ static std::integral_constant<bool,
+ noexcept(static_cast<bool>(std::declval<const T2 &>()
+ == std::declval<const T2 &>()))>
+ fn(const T2 &);
+
+public:
+ static constexpr bool value = decltype(fn(std::declval<const T &>()))::value;
+};
+
+template <typename T>
+struct variant_is_nothrow_less_comparable
+{
+private:
+ static std::false_type fn(...);
+ template <typename T2>
+ static std::integral_constant<bool,
+ noexcept(static_cast<bool>(std::declval<const T2 &>()
+ < std::declval<const T2 &>()))>
+ fn(const T2 &);
+
+public:
+ static constexpr bool value = decltype(fn(std::declval<const T &>()))::value;
+};
+
template <typename... Types>
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 <std::size_t index>
constexpr variant_values(in_place_index_t<index>) noexcept : value()
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 <typename T, typename... Types>
static_assert(!std::is_void<T>::value, "invalid variant member type");
static_assert(!std::is_reference<T>::value, "invalid variant member type");
static_assert(!std::is_array<T>::value, "invalid variant member type");
+ static_assert(!std::is_const<T>::value, "invalid variant member type");
+ static_assert(!std::is_volatile<T>::value, "invalid variant member type");
+ static_assert(std::is_object<T>::value, "invalid variant member type");
T current_value;
variant_values<Types...> other_values;
static constexpr bool is_copy_constructible =
static constexpr bool is_trivially_destructible =
std::is_trivially_destructible<T>::value
&& variant_values<Types...>::is_trivially_destructible;
- static constexpr bool is_swappable =
- is_swappable_v<T> && std::is_move_constructible<T> && variant_values<Types...>::
- is_swappable;
+ static constexpr bool is_swappable = is_swappable_v<T> && std::is_move_constructible<T>::value
+ && variant_values<Types...>::is_swappable;
static constexpr bool is_nothrow_swappable =
- is_nothrow_swappable_v<T> && std::
- is_nothrow_move_constructible<T> && variant_values<Types...>::
- is_nothrow_swappable;
+ is_nothrow_swappable_v<T> && std::is_nothrow_move_constructible<T>::value
+ && variant_values<Types...>::is_nothrow_swappable;
+ static constexpr bool is_equals_comparable =
+ variant_is_equals_comparable<T>::value && variant_values<Types...>::is_equals_comparable;
+ static constexpr bool is_less_comparable =
+ variant_is_less_comparable<T>::value && variant_values<Types...>::is_less_comparable;
+ static constexpr bool is_nothrow_equals_comparable =
+ variant_is_nothrow_equals_comparable<T>::value
+ && variant_values<Types...>::is_nothrow_equals_comparable;
+ static constexpr bool is_nothrow_less_comparable =
+ variant_is_nothrow_less_comparable<T>::value
+ && variant_values<Types...>::is_nothrow_less_comparable;
template <typename T2 = T,
typename = typename std::enable_if<std::is_default_constructible<T2>::value>::type>
constexpr variant_values() noexcept(std::is_nothrow_default_constructible<T2>::value)
template <typename U>
static constexpr std::size_t index_from_type() noexcept
{
- std::size_t next = variant_values<Types...>::index_from_type<U>();
+ std::size_t next = variant_values<Types...>::template index_from_type<U>();
if(std::is_same<U, T>::value && next == variant_npos)
return 0;
if(next == variant_npos)
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<bool>(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<bool>(current_value < rt.current_value);
+ return other_values.is_equal(rt.other_values, index - 1);
+ }
};
template <std::size_t Index, typename... Types>
{ \
typedef Return_Type (*Dispatch_Function)( \
Fn && fn, Const variant_values<Types...> & values, Args && ... args); \
- static const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
+ const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
static_cast<Dispatch_Function>( \
[](Fn &&fn, Const variant_values<Types...> &values, Args &&... args) \
-> Return_Type \
{ \
typedef Return_Type (*Dispatch_Function)( \
Fn && fn, Const variant_values<Types...> & values, Args && ... args); \
- static const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
+ const Dispatch_Function dispatch_functions[sizeof...(Types)] = { \
static_cast<Dispatch_Function>( \
[](Fn &&fn, Const variant_values<Types...> &values, Args &&... args) \
-> Return_Type \
typename... Types,
typename Deduced_Type = typename decltype(
variant_hypothetical_overload_set<Types...>::fn(std::declval<T>()))::type,
- std::size_t Index = variant_values<Types...>::index_from_type<Deduced_Type>(),
+ std::size_t Index = variant_values<Types...>::template index_from_type<Deduced_Type>(),
typename = typename std::enable_if<(Index < sizeof...(Types))>::type>
constexpr std::size_t variant_conversion_deduce_index() noexcept
{
template <typename T, typename... Types>
using variant_conversion_deduce_type =
- variant_alternative_t<variant_conversion_deduce_index<T, Types...>(), Types...>;
+ variant_alternative_t<variant_conversion_deduce_index<T, Types...>(), variant<Types...>>;
template <std::size_t Type_Count>
struct variant_index_type
{
static constexpr bool value = true;
};
+
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types &>()))...>::type
+ variant_dispatch(Fn &&fn, variant<Types...> &v, Args &&... args);
+
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<const Types &>()))...>::type
+ variant_dispatch(Fn &&fn, const variant<Types...> &v, Args &&... args);
+
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types &&>()))...>::type
+ variant_dispatch(Fn &&fn, variant<Types...> &&v, Args &&... args);
+
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<const Types &&>()))...>::type
+ variant_dispatch(Fn &&fn, const variant<Types...> &&v, Args &&... args);
}
template <typename... Types>
typename std::enable_if<detail::variant_values<Types...>::is_copy_constructible>::type>
variant(const variant &rt) noexcept(
detail::variant_values<Types...>::is_nothrow_copy_constructible)
- : base(variant_npos, in_place_index<variant_npos>())
+ : base(variant_npos, in_place_index<variant_npos>)
{
values.copy_construct(rt.values, rt.index_value.get());
index_value = rt.index_value;
typename =
typename std::enable_if<detail::variant_values<Types...>::is_move_constructible>::type>
variant(variant &&rt) noexcept(detail::variant_values<Types...>::is_nothrow_move_constructible)
- : base(variant_npos, in_place_index<variant_npos>())
+ : base(variant_npos, in_place_index<variant_npos>)
{
values.move_construct(std::move(rt.values), rt.index_value.get());
index_value = rt.index_value;
}
template <typename T,
typename... Args,
- std::size_t Index = detail::variant_values<Types...>::index_from_type<T>(),
+ std::size_t Index = detail::variant_values<Types...>::template index_from_type<T>(),
typename = typename std::enable_if<(Index < sizeof...(Types))
&& std::is_constructible<T, Args...>::value>::type>
constexpr explicit variant(in_place_type_t<T>, Args &&... args) noexcept(
typename T,
typename U,
typename... Args,
- std::size_t Index = detail::variant_values<Types...>::index_from_type<T>(),
+ std::size_t Index = detail::variant_values<Types...>::template index_from_type<T>(),
typename = typename std::
enable_if<(Index < sizeof...(Types))
&& std::is_constructible<T, std::initializer_list<U>, Args...>::value>::type>
}
template <typename T,
typename... Args,
- std::size_t Index = detail::variant_values<Types...>::index_from_type<T>(),
+ std::size_t Index = detail::variant_values<Types...>::template index_from_type<T>(),
typename = typename std::enable_if<(Index < sizeof...(Types))
&& std::is_constructible<T, Args...>::value>::type>
void emplace(Args &&... args)
typename T,
typename U,
typename... Args,
- std::size_t Index = detail::variant_values<Types...>::index_from_type<T>(),
+ std::size_t Index = detail::variant_values<Types...>::template index_from_type<T>(),
typename = typename std::
enable_if<(Index < sizeof...(Types))
&& std::is_constructible<T, std::initializer_list<U>, Args...>::value>::type>
*this = std::move(temp);
}
}
+ template <typename T, typename... Types2>
+ friend constexpr bool holds_alternative(const variant<Types2...> &v) noexcept;
+ template <std::size_t Index, typename... Types2>
+ friend constexpr variant_alternative_t<Index, variant<Types2...>> &get(variant<Types2...> &v);
+ template <std::size_t Index, typename... Types2>
+ friend constexpr const variant_alternative_t<Index, variant<Types2...>> &get(
+ const variant<Types2...> &v);
+ template <typename... Types2>
+ friend constexpr
+ typename std::enable_if<detail::variant_values<Types2...>::is_equals_comparable, bool>::type
+ operator==(const variant<Types2...> &l, const variant<Types2...> &r) noexcept(
+ detail::variant_values<Types2...>::is_nothrow_equals_comparable);
+ template <typename... Types2>
+ friend constexpr
+ typename std::enable_if<detail::variant_values<Types2...>::is_less_comparable, bool>::type
+ operator<(const variant<Types2...> &l, const variant<Types2...> &r) noexcept(
+ detail::variant_values<Types2...>::is_nothrow_less_comparable);
+ template <typename Fn, typename... Types2, typename... Args>
+ friend typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types2 &>()))...>::type
+ detail::variant_dispatch(Fn &&fn, variant<Types2...> &v, Args &&... args);
+ template <typename Fn, typename... Types2, typename... Args>
+ friend typename std::common_type<decltype(
+ std::declval<Fn>()(std::declval<const Types2 &>()))...>::type
+ detail::variant_dispatch(Fn &&fn, const variant<Types2...> &v, Args &&... args);
+ template <typename Fn, typename... Types2, typename... Args>
+ friend
+ typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types2 &&>()))...>::type
+ detail::variant_dispatch(Fn &&fn, variant<Types2...> &&v, Args &&... args);
+ template <typename Fn, typename... Types2, typename... Args>
+ friend typename std::common_type<decltype(
+ std::declval<Fn>()(std::declval<const Types2 &&>()))...>::type
+ detail::variant_dispatch(Fn &&fn, const variant<Types2...> &&v, Args &&... args);
};
-#error finish
+
+template <typename T, typename... Types>
+constexpr bool holds_alternative(const variant<Types...> &v) noexcept
+{
+ constexpr std::size_t index = detail::variant_values<Types...>::template index_from_type<T>();
+ static_assert(index != variant_npos, "");
+ return v.index_value.get() == index;
+}
+
+template <std::size_t Index, typename... Types>
+constexpr variant_alternative_t<Index, variant<Types...>> &get(variant<Types...> &v)
+{
+ static_assert(Index < sizeof...(Types), "");
+ if(v.index_value.get() == Index)
+ return detail::variant_get<Index, Types...>::get(v.values);
+ throw bad_variant_access();
+}
+
+template <std::size_t Index, typename... Types>
+constexpr const variant_alternative_t<Index, variant<Types...>> &get(const variant<Types...> &v)
+{
+ static_assert(Index < sizeof...(Types), "");
+ if(v.index_value.get() == Index)
+ return detail::variant_get<Index, Types...>::get(v.values);
+ throw bad_variant_access();
+}
+
+template <std::size_t Index, typename... Types>
+constexpr const variant_alternative_t<Index, variant<Types...>> &&get(const variant<Types...> &&v)
+{
+ return std::move(get<Index>(v));
+}
+
+template <std::size_t Index, typename... Types>
+constexpr variant_alternative_t<Index, variant<Types...>> &&get(variant<Types...> &&v)
+{
+ return std::move(get<Index>(v));
+}
+
+template <typename T, typename... Types>
+constexpr const T &get(const variant<Types...> &v)
+{
+ return get<detail::variant_values<Types...>::template index_from_type<T>()>(v);
+}
+
+template <typename T, typename... Types>
+constexpr T &get(variant<Types...> &v)
+{
+ return get<detail::variant_values<Types...>::template index_from_type<T>()>(v);
+}
+
+template <typename T, typename... Types>
+constexpr const T &&get(const variant<Types...> &&v)
+{
+ return get<detail::variant_values<Types...>::template index_from_type<T>()>(std::move(v));
+}
+
+template <typename T, typename... Types>
+constexpr T &&get(variant<Types...> &&v)
+{
+ return get<detail::variant_values<Types...>::template index_from_type<T>()>(std::move(v));
+}
+
+template <std::size_t Index, typename... Types>
+constexpr const variant_alternative_t<Index, variant<Types...>> *get_if(
+ const variant<Types...> *v) noexcept
+{
+ static_assert(Index < sizeof...(Types), "");
+ if(!v || v->index() != Index)
+ return nullptr;
+ return std::addressof(get<Index>(*v));
+}
+
+template <std::size_t Index, typename... Types>
+constexpr variant_alternative_t<Index, variant<Types...>> *get_if(variant<Types...> *v) noexcept
+{
+ static_assert(Index < sizeof...(Types), "");
+ if(!v || v->index() != Index)
+ return nullptr;
+ return std::addressof(get<Index>(*v));
+}
+
+template <typename T, typename... Types>
+constexpr const T *get_if(const variant<Types...> *v) noexcept
+{
+ return get_if<detail::variant_values<Types...>::template index_from_type<T>()>(v);
+}
+
+template <typename T, typename... Types>
+constexpr T *get_if(variant<Types...> *v) noexcept
+{
+ return get_if<detail::variant_values<Types...>::template index_from_type<T>()>(v);
+}
+
+template <typename... Types>
+constexpr
+ typename std::enable_if<detail::variant_values<Types...>::is_equals_comparable, bool>::type
+ operator==(const variant<Types...> &l, const variant<Types...> &r) noexcept(
+ detail::variant_values<Types...>::is_nothrow_equals_comparable)
+{
+ return l.index_value.get() == r.index_value.get()
+ && l.values.is_equal(r.values, l.index_value.get());
+}
+
+template <typename... Types>
+constexpr
+ typename std::enable_if<detail::variant_values<Types...>::is_equals_comparable, bool>::type
+ operator!=(const variant<Types...> &l, const variant<Types...> &r) noexcept(
+ detail::variant_values<Types...>::is_nothrow_equals_comparable)
+{
+ return !operator==(l, r);
+}
+
+template <typename... Types>
+constexpr typename std::enable_if<detail::variant_values<Types...>::is_less_comparable, bool>::type
+ operator<(const variant<Types...> &l, const variant<Types...> &r) noexcept(
+ detail::variant_values<Types...>::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 <typename... Types>
+constexpr typename std::enable_if<detail::variant_values<Types...>::is_less_comparable, bool>::type
+ operator>(const variant<Types...> &l, const variant<Types...> &r) noexcept(
+ detail::variant_values<Types...>::is_nothrow_less_comparable)
+{
+ return operator<(r, l);
+}
+
+template <typename... Types>
+constexpr typename std::enable_if<detail::variant_values<Types...>::is_less_comparable, bool>::type
+ operator>=(const variant<Types...> &l, const variant<Types...> &r) noexcept(
+ detail::variant_values<Types...>::is_nothrow_less_comparable)
+{
+ return !operator<(l, r);
+}
+
+template <typename... Types>
+constexpr typename std::enable_if<detail::variant_values<Types...>::is_less_comparable, bool>::type
+ operator<=(const variant<Types...> &l, const variant<Types...> &r) noexcept(
+ detail::variant_values<Types...>::is_nothrow_less_comparable)
+{
+ return !operator<(r, l);
+}
+
+namespace detail
+{
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types &>()))...>::type
+ variant_dispatch(Fn &&fn, variant<Types...> &v, Args &&... args)
+{
+ return variant_dispatch(
+ std::forward<Fn>(fn), v.values, v.index_value.get(), std::forward<Args>(args)...);
+}
+
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<const Types &>()))...>::type
+ variant_dispatch(Fn &&fn, const variant<Types...> &v, Args &&... args)
+{
+ return variant_dispatch(
+ std::forward<Fn>(fn), v.values, v.index_value.get(), std::forward<Args>(args)...);
+}
+
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<Types &&>()))...>::type
+ variant_dispatch(Fn &&fn, variant<Types...> &&v, Args &&... args)
+{
+ return variant_dispatch(std::forward<Fn>(fn),
+ std::move(v.values),
+ v.index_value.get(),
+ std::forward<Args>(args)...);
+}
+
+template <typename Fn, typename... Types, typename... Args>
+typename std::common_type<decltype(std::declval<Fn>()(std::declval<const Types &&>()))...>::type
+ variant_dispatch(Fn &&fn, const variant<Types...> &&v, Args &&... args)
+{
+ return variant_dispatch(std::forward<Fn>(fn),
+ std::move(v.values),
+ v.index_value.get(),
+ std::forward<Args>(args)...);
+}
+
+template <typename Fn, typename... Types>
+decltype(variant_dispatch(std::declval<Fn>(), std::declval<variant<Types...> &>())) variant_visit(
+ Fn &&fn, variant<Types...> &v)
+{
+ return variant_dispatch(std::forward<Fn>(fn), v);
+}
+
+template <typename Fn, typename... Types>
+decltype(variant_dispatch(std::declval<Fn>(), std::declval<const variant<Types...> &>()))
+ variant_visit(Fn &&fn, const variant<Types...> &v)
+{
+ return variant_dispatch(std::forward<Fn>(fn), v);
+}
+
+template <typename Fn, typename... Types>
+decltype(variant_dispatch(std::declval<Fn>(), std::declval<variant<Types...> &&>())) variant_visit(
+ Fn &&fn, variant<Types...> &&v)
+{
+ return variant_dispatch(std::forward<Fn>(fn), std::move(v));
+}
+
+template <typename Fn, typename... Types>
+decltype(variant_dispatch(std::declval<Fn>(), std::declval<const variant<Types...> &&>()))
+ variant_visit(Fn &&fn, const variant<Types...> &&v)
+{
+ return variant_dispatch(std::forward<Fn>(fn), std::move(v));
+}
+
+template <typename Fn, typename... Types, typename Variant2, typename... Variants>
+auto variant_visit(Fn &&fn,
+ const variant<Types...> &&v,
+ Variant2 &&variant2,
+ Variants &&... variants)
+{
+ return variant_dispatch(
+ [&](auto &&value)
+ {
+ return variant_visit(
+ [&](auto &&... args)
+ {
+ return std::forward<Fn>(fn)(std::forward<decltype(value)>(value),
+ std::forward<decltype(args)>(args)...);
+ },
+ std::forward<Variant2>(variant2),
+ std::forward<Variants>(variants)...);
+ },
+ std::move(v));
+}
+}
+
+template <typename Fn, typename... Variants>
+auto visit(Fn &&fn, Variants &&... variants)
+{
+ return detail::variant_visit(std::forward<Fn>(fn), std::forward<Variants>(variants)...);
+}
}
}
}
};
+template <typename... Types>
+struct hash<vulkan_cpu::util::variant<Types...>>
+{
+ constexpr std::size_t operator()(const vulkan_cpu::util::variant<Types...> &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<typename std::decay<decltype(v)>::type>()(v);
+ },
+ v);
+ }
+};
+
template <typename... Types,
typename = typename std::
enable_if<vulkan_cpu::util::detail::variant_values<Types...>::is_swappable>::type>