util::variant implemented
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 1 Jun 2017 06:06:54 +0000 (23:06 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 1 Jun 2017 06:06:54 +0000 (23:06 -0700)
src/util/CMakeLists.txt
src/util/invoke.cpp [new file with mode: 0644]
src/util/invoke.h [new file with mode: 0644]
src/util/variant.cpp [new file with mode: 0644]
src/util/variant.h

index a775745783a32ec8ca2f866d63cd0fe699f4afac..2059497383c071cecb405032d6283bb552952187 100644 (file)
 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 (file)
index 0000000..67bf132
--- /dev/null
@@ -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 (file)
index 0000000..0a8f05c
--- /dev/null
@@ -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 <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_ */
diff --git a/src/util/variant.cpp b/src/util/variant.cpp
new file mode 100644 (file)
index 0000000..5854282
--- /dev/null
@@ -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"
index 19ef314cfedefd84a827fe02ed14d8c72f06d7b6..f32aa2a2e95f2c648230c32cf7783d889a2a190d 100644 (file)
@@ -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<Index, const T>
 };
 
 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;
 };
@@ -170,11 +172,69 @@ struct variant_hypothetical_overload_set<T, Types...>
 };
 
 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
 {
@@ -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 <std::size_t index>
     constexpr variant_values(in_place_index_t<index>) 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 <typename T, typename... Types>
@@ -227,6 +299,9 @@ union variant_values<T, 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 =
@@ -254,13 +329,21 @@ union variant_values<T, Types...>
     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)
@@ -304,7 +387,7 @@ union variant_values<T, Types...>
     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)
@@ -357,6 +440,20 @@ union variant_values<T, Types...>
         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>
@@ -423,7 +520,7 @@ struct variant_get<0, T, 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                                                               \
@@ -472,7 +569,7 @@ struct variant_get<0, T, 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                                                               \
@@ -517,7 +614,7 @@ template <typename T,
           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
 {
@@ -526,7 +623,7 @@ 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
@@ -630,6 +727,22 @@ struct variant_is_in_place_type<in_place_type_t<T>>
 {
     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>
@@ -660,7 +773,7 @@ public:
             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;
@@ -669,7 +782,7 @@ public:
         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;
@@ -690,7 +803,7 @@ public:
     }
     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(
@@ -702,7 +815,7 @@ public:
         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>
@@ -812,7 +925,7 @@ public:
     }
     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)
@@ -823,7 +936,7 @@ public:
         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>
@@ -886,8 +999,279 @@ public:
             *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)...);
+}
 }
 }
 
@@ -902,6 +1286,23 @@ struct hash<vulkan_cpu::util::monostate>
     }
 };
 
+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>