generate_spirv_parser is complete, commit everything I missed last time
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 22 Jun 2017 08:29:02 +0000 (01:29 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 22 Jun 2017 08:29:02 +0000 (01:29 -0700)
CMakeLists.txt
src/generate_spirv_parser/ast.h
src/generate_spirv_parser/generate.cpp
src/generate_spirv_parser/generate.h
src/generate_spirv_parser/generate_spirv_parser.cpp
src/generate_spirv_parser/parser.cpp
src/generate_spirv_parser/patch.cpp [new file with mode: 0644]
src/generate_spirv_parser/patch.h [new file with mode: 0644]
src/util/variant.h

index e9ef5d7d178d7fbe5ed3967a59dc778f0fac50c0..6890d6be1baf43e55697bba3c66f575c817fec21 100644 (file)
@@ -27,5 +27,5 @@ project(vulkan-cpu CXX)
 if(NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
   message(FATAL_ERROR "compiler is not clang")
 endif()
-add_compile_options(-Wall)
+add_compile_options(-Wall -ftemplate-depth=1024)
 add_subdirectory(src)
index d3fdefac89f2e6190569c48945b6bf0b094bd8c5..e664051264ac8d231e1379f25605060bfd00ed63 100644 (file)
@@ -25,6 +25,8 @@
 #define GENERATE_SPIRV_PARSER_AST_H_
 
 #include "json/json.h"
+#include "util/optional.h"
+#include "util/string_view.h"
 #include <cstdint>
 #include <vector>
 #include <string>
@@ -232,6 +234,46 @@ struct Operand_kinds
             return "";
         }
         std::string kind;
+        enum class Literal_kind
+        {
+            literal_integer,
+            literal_string,
+            literal_context_dependent_number,
+            literal_ext_inst_integer,
+            literal_spec_constant_op_integer,
+        };
+        static constexpr const char *get_json_name_from_literal_kind(Literal_kind kind) noexcept
+        {
+            switch(kind)
+            {
+            case Literal_kind::literal_integer:
+                return "LiteralInteger";
+            case Literal_kind::literal_string:
+                return "LiteralString";
+            case Literal_kind::literal_context_dependent_number:
+                return "LiteralContextDependentNumber";
+            case Literal_kind::literal_ext_inst_integer:
+                return "LiteralExtInstInteger";
+            case Literal_kind::literal_spec_constant_op_integer:
+                return "LiteralSpecConstantOpInteger";
+            }
+            return "";
+        }
+        static util::optional<Literal_kind> get_literal_kind_from_json_name(
+            util::string_view name) noexcept
+        {
+            if(name == "LiteralInteger")
+                return Literal_kind::literal_integer;
+            if(name == "LiteralString")
+                return Literal_kind::literal_string;
+            if(name == "LiteralContextDependentNumber")
+                return Literal_kind::literal_context_dependent_number;
+            if(name == "LiteralExtInstInteger")
+                return Literal_kind::literal_ext_inst_integer;
+            if(name == "LiteralSpecConstantOpInteger")
+                return Literal_kind::literal_spec_constant_op_integer;
+            return {};
+        }
         struct Enumerants
         {
             static constexpr const char *get_json_key_name() noexcept
index ff26f95fb85cc029014fcd87ebc2f0e528b7cbda..7a07d35526af6db9880bb6af54894287bdebae5c 100644 (file)
@@ -151,11 +151,6 @@ constexpr bool is_digit(char ch) noexcept
         return true;
     return false;
 }
-
-constexpr bool is_identifier_continue(char ch) noexcept
-{
-    return is_identifier_start(ch) || is_digit(ch);
-}
 }
 
 std::string Generator::get_enumerant_name(const char *enumeration_name,
@@ -1046,17 +1041,32 @@ constexpr Word magic_number = )")
             case ast::Operand_kinds::Operand_kind::Category::literal:
             {
                 auto &doc = util::get<ast::Operand_kinds::Operand_kind::Doc>(operand_kind->value);
+                auto literal_kind =
+                    ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
+                        operand_kind->kind);
+                if(!literal_kind)
+                    throw Generate_error("bad literal kind");
                 auto base_type = "std::vector<Word>";
-                if(operand_kind->kind == "LiteralInteger")
-                    base_type = "std::uint32_t"; // TODO: fix after determining if LiteralInteger
-                // can be multiple words
-                else if(operand_kind->kind == "LiteralString")
+                switch(*literal_kind)
+                {
+                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
+                    // TODO: fix after determining if LiteralInteger can be multiple words
+                    base_type = "std::uint32_t";
+                    break;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
                     base_type = "std::string";
-                else if(operand_kind->kind == "LiteralExtInstInteger")
+                    break;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::
+                    literal_context_dependent_number:
+                    break;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
                     base_type = "Word";
-                else if(operand_kind->kind == "LiteralSpecConstantOpInteger")
+                    break;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::
+                    literal_spec_constant_op_integer:
                     base_type = "Op";
-#warning finish
+                    break;
+                }
                 state << "\n"
                          "/** ";
                 bool was_last_star = false;
@@ -1357,8 +1367,6 @@ struct )") << struct_name << indent(true, R"(
             }
             state << "};\n";
         }
-
-#warning finish
         write_namespaces_end(state, spirv_namespace_names);
         write_file_guard_end(state);
     }
@@ -1468,7 +1476,6 @@ virtual void handle_id_bound(Word id_bound) = 0;
                 state << indent("virtual void handle_instruction(") << struct_name
                       << " instruction) = 0;\n";
             }
-#warning finish
         }
         state << indent(R"(};
 
@@ -1503,7 +1510,6 @@ virtual void handle_id_bound(Word id_bound) override;
                 state << indent("void ") << dump_function_name << "(const std::vector<"
                       << get_operand_with_parameters_name(state, operand_kind) << "> &values);\n";
             }
-#warning finish
         }
         state << "};\n"
                  "\n"
@@ -1698,19 +1704,19 @@ if(parse_error)
                 }
                 case ast::Operand_kinds::Operand_kind::Category::literal:
                 {
-                    if(operand_kind.kind == "LiteralInteger")
+                    auto literal_kind =
+                        ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
+                            operand_kind.kind);
+                    if(!literal_kind)
+                        throw Generate_error("bad literal kind");
+                    switch(*literal_kind)
                     {
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
                         // TODO: fix after determining if LiteralInteger can be multiple words
                         state << indent(R"(value = words[word_index++];
 )");
-                    }
-                    else if(operand_kind.kind == "LiteralExtInstInteger")
-                    {
-                        state << indent(R"(value = words[word_index++];
-)");
-                    }
-                    else if(operand_kind.kind == "LiteralString")
-                    {
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
                         state << indent(
                             R"(value.clear();
 bool done = false;
@@ -1736,16 +1742,9 @@ while(!done)
 `}
 }
 )");
-                    }
-                    else if(operand_kind.kind == "LiteralSpecConstantOpInteger")
-                    {
-#warning finish
-                        state << indent(R"(value = static_cast<)") << op_enum_name
-                              << indent(true, R"(>(words[word_index++]);
-)");
-                    }
-                    else
-                    {
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::
+                        literal_context_dependent_number:
                         state << indent(
                             R"(static_assert(std::is_same<decltype(value), std::vector<Word> &>::value, "missing parse code for operand kind");
 value.clear();
@@ -1753,6 +1752,17 @@ value.reserve(word_count - word_index);
 while(word_index < word_count)
 `value.push_back(words[word_index++]);
 )");
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
+                        state << indent(R"(value = words[word_index++];
+)");
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::
+                        literal_spec_constant_op_integer:
+                        state << indent(R"(value = static_cast<)") << op_enum_name
+                              << indent(true, R"(>(words[word_index++]);
+)");
+                        break;
                     }
                     break;
                 }
@@ -1908,10 +1918,8 @@ static std::unique_ptr<Parse_error> parse(const Word *words, std::size_t word_co
 `return nullptr;
 }
 )");
-#warning finish
         }
         state << "};\n";
-#warning finish
         write_namespaces_end(state, spirv_namespace_names);
         write_file_guard_end(state);
     }
@@ -2126,8 +2134,8 @@ else if(first)
                                 state << indent(2)
                                       << Parser_header_generator::get_dump_operand_function_name(
                                              parameter)
-                                      << "(parameters->" << get_member_name_from_parameter(parameter)
-                                      << ");\n";
+                                      << "(parameters->"
+                                      << get_member_name_from_parameter(parameter) << ");\n";
                             }
                             state << indent(R"a(`}
 `os << ")";
@@ -2182,36 +2190,25 @@ else
                 }
                 case ast::Operand_kinds::Operand_kind::Category::literal:
                 {
-                    if(operand_kind.kind == "LiteralInteger")
+                    auto literal_kind =
+                        ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
+                            operand_kind.kind);
+                    if(!literal_kind)
+                        throw Generate_error("bad literal kind");
+                    switch(*literal_kind)
                     {
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
                         state << indent(
                             R"(os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x");
 )");
-                    }
-                    else if(operand_kind.kind == "LiteralExtInstInteger")
-                    {
-                        state << indent(
-                            R"(os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x");
-)");
-                    }
-                    else if(operand_kind.kind == "LiteralString")
-                    {
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
                         state << indent(
                             R"(json::ast::String_value::write(os, value);
 )");
-                    }
-                    else if(operand_kind.kind == "LiteralSpecConstantOpInteger")
-                    {
-                        state << indent(R"(if(util::Enum_traits<)") << op_enum_name
-                              << indent(true, R"(>::find_value(value) == util::Enum_traits<)")
-                              << op_enum_name << indent(true, R"(>::npos)
-`os << json::ast::Number_value::unsigned_integer_to_string(static_cast<Word>(value));
-else
-`os << get_enumerant_name(value);
-)");
-                    }
-                    else
-                    {
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::
+                        literal_context_dependent_number:
                         state << indent(
                             R"(static_assert(std::is_same<decltype(value), const std::vector<Word> &>::value, "missing dump code for operand kind");
 auto separator = "";
@@ -2224,6 +2221,22 @@ for(Word word : value)
 }
 os << "}";
 )");
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
+                        state << indent(
+                            R"(os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x");
+)");
+                        break;
+                    case ast::Operand_kinds::Operand_kind::Literal_kind::
+                        literal_spec_constant_op_integer:
+                        state << indent(R"(if(util::Enum_traits<)") << op_enum_name
+                              << indent(true, R"(>::find_value(value) == util::Enum_traits<)")
+                              << op_enum_name << indent(true, R"(>::npos)
+`os << json::ast::Number_value::unsigned_integer_to_string(static_cast<Word>(value));
+else
+`os << get_enumerant_name(value);
+)");
+                        break;
                     }
                     break;
                 }
index 4cfc4f62a88664c836147bf2e58f0e2ac183014b..b873b2253cf9b76186206ac348bd0e9f4b9d799d 100644 (file)
@@ -364,7 +364,11 @@ protected:
     static std::string get_member_name_from_operand(
         const ast::Instructions::Instruction::Operands::Operand &operand);
     static std::string get_member_name_from_parameter(
-        const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter &parameter);
+        const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter
+            &parameter);
+    static std::string get_member_name_from_enumerant(
+        const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant
+            &enumerant);
     static const ast::Operand_kinds::Operand_kind &get_operand_kind_from_string(
         Generator_state &state, const std::string &operand_kind_str)
     {
@@ -396,6 +400,12 @@ protected:
         return get_operand_with_parameters_name(
             state, get_operand_kind_from_string(state, operand_kind_str));
     }
+    static std::string get_operand_with_parameters_name(
+        Generator_state &state, const ast::Instructions::Instruction::Operands::Operand &operand)
+    {
+        return get_operand_with_parameters_name(state,
+                                                get_operand_kind_from_string(state, operand.kind));
+    }
     static std::string get_enum_name(std::string operand_kind_str)
     {
         return operand_kind_str;
index 8888aa97ea32644c70624b43572efc32fefa57ff..c03e25d58976836d59a598122f6bee0a85a5d61a 100644 (file)
@@ -60,8 +60,6 @@ int generate_spirv_parser_main(int argc, char **argv)
             {
                 generator->run(generate::Generator::Generator_args(output_directory), ast);
             }
-#warning finish
-            std::cerr << "generate_spirv_parser is not finished being implemented" << std::endl;
             return 0;
         }
         catch(parser::Parse_error &e)
index d1bd5439d0e3719ed20bfa13b6c1a88faeee6edf..f7f7c7610ad9c5e758d3cc5fb7e616c72f70c156 100644 (file)
@@ -495,7 +495,12 @@ ast::Operand_kinds::Operand_kind parse_operand_kinds_operand_kind(
         kind_name,
         [&](json::ast::Value &entry_value, const Path_builder_base *path_builder)
         {
-            return parse_identifier_string(std::move(entry_value), path_builder, kind_name);
+            auto retval = parse_identifier_string(std::move(entry_value), path_builder, kind_name);
+            if(category == ast::Operand_kinds::Operand_kind::Category::literal
+               && !ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(retval))
+                throw Parse_error(
+                    entry_value.location, path_builder->path(), "unknown literal kind");
+            return retval;
         });
     util::optional<ast::Operand_kinds::Operand_kind::Value> operand_kind_value;
     for(auto &entry : operand_kind_object.values)
diff --git a/src/generate_spirv_parser/patch.cpp b/src/generate_spirv_parser/patch.cpp
new file mode 100644 (file)
index 0000000..8eb062e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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 "patch.h"
+
+namespace vulkan_cpu
+{
+namespace generate_spirv_parser
+{
+void Ast_patch::run(ast::Top_level &top_level, std::ostream *log_output) const
+{
+    auto name = get_name();
+    if(log_output)
+        *log_output << "PATCH " << name << ": checking if applicable" << std::endl;
+    if(apply(top_level))
+    {
+        if(log_output)
+            *log_output << "PATCH " << name << ": applied" << std::endl;
+    }
+    else if(log_output)
+        *log_output << "PATCH " << name << ": not applicable" << std::endl;
+}
+
+bool Ast_patches::Add_image_operands_grad_parameter_names::apply(ast::Top_level &top_level) const
+{
+    for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
+    {
+        if(operand_kind.kind != "ImageOperands")
+            continue;
+        auto *enumerants =
+            util::get_if<ast::Operand_kinds::Operand_kind::Enumerants>(&operand_kind.value);
+        if(enumerants)
+        {
+            for(auto &enumerant : enumerants->enumerants)
+            {
+                if(enumerant.enumerant != "Grad")
+                    continue;
+                if(enumerant.parameters.parameters.size() != 2)
+                    return false;
+                auto &dx_param = enumerant.parameters.parameters[0];
+                if(!dx_param.name.empty())
+                    return false;
+                auto &dy_param = enumerant.parameters.parameters[1];
+                if(!dy_param.name.empty())
+                    return false;
+                dx_param.name = "dx";
+                dy_param.name = "dy";
+                return true;
+            }
+        }
+        return false;
+    }
+    return false;
+}
+
+const char *Ast_patches::Add_image_operands_grad_parameter_names::get_name() const noexcept
+{
+    return "Add_image_operands_grad_parameter_names";
+}
+
+std::vector<const Ast_patch *> Ast_patches::get_patches()
+{
+    static const auto add_image_operands_grad_parameter_names =
+        Add_image_operands_grad_parameter_names();
+    return {
+        &add_image_operands_grad_parameter_names,
+    };
+}
+}
+}
diff --git a/src/generate_spirv_parser/patch.h b/src/generate_spirv_parser/patch.h
new file mode 100644 (file)
index 0000000..eb253ae
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 GENERATE_SPIRV_PARSER_PATCH_H_
+#define GENERATE_SPIRV_PARSER_PATCH_H_
+
+#include "ast.h"
+#include <ostream>
+#include <memory>
+
+namespace vulkan_cpu
+{
+namespace generate_spirv_parser
+{
+struct Ast_patch
+{
+    constexpr Ast_patch() noexcept
+    {
+    }
+    virtual ~Ast_patch() = default;
+
+protected:
+    virtual bool apply(ast::Top_level &top_level) const = 0;
+
+public:
+    virtual const char *get_name() const noexcept = 0;
+    void run(ast::Top_level &top_level, std::ostream *log_output = nullptr) const;
+};
+
+struct Ast_patches
+{
+    struct Add_image_operands_grad_parameter_names final : public Ast_patch
+    {
+        using Ast_patch::Ast_patch;
+    protected:
+        virtual bool apply(ast::Top_level &top_level) const override;
+
+    public:
+        virtual const char *get_name() const noexcept override;
+    };
+    static std::vector<const Ast_patch *> get_patches();
+};
+}
+}
+
+#endif /* GENERATE_SPIRV_PARSER_PATCH_H_ */
index da5ae14eb4232dc736cc04194c1614f48db55768..288ac14074df1d1e6ae3ccff0aa3be993659fb65 100644 (file)
@@ -244,7 +244,7 @@ template <typename... Types>
 constexpr bool variant_is_trivially_destructible() noexcept
 {
     bool values[] = {
-        std::is_trivially_destructible<Types>::value...,
+        true, std::is_trivially_destructible<Types>::value...,
     };
     for(bool v : values)
         if(!v)
@@ -312,201 +312,182 @@ template <typename... Types>
 using Variant_values =
     Variant_values_implementation<variant_is_trivially_destructible<Types...>(), Types...>;
 
-#define VULKAN_CPU_UTIL_VARIANT_VALUES(Is_Trivially_Destructible, Destructor)                                    \
-    template <typename T, typename... Types>                                                                     \
-    union Variant_values_implementation<Is_Trivially_Destructible, T, Types...>                                  \
-    {                                                                                                            \
-        typedef T Type_0;                                                                                        \
-        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_implementation<Is_Trivially_Destructible, Types...> other_values;                         \
-        static constexpr bool is_copy_constructible =                                                            \
-            std::is_copy_constructible<T>::value                                                                 \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_copy_constructible;                                   \
-        static constexpr bool is_move_constructible =                                                            \
-            std::is_move_constructible<T>::value                                                                 \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_move_constructible;                                   \
-        static constexpr bool is_nothrow_copy_constructible =                                                    \
-            std::is_nothrow_copy_constructible<T>::value                                                         \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_nothrow_copy_constructible;                           \
-        static constexpr bool is_nothrow_move_constructible =                                                    \
-            std::is_nothrow_move_constructible<T>::value                                                         \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_nothrow_move_constructible;                           \
-        static constexpr bool is_copy_assignable =                                                               \
-            std::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value                            \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_copy_assignable;                                      \
-        static constexpr bool is_move_assignable =                                                               \
-            std::is_move_assignable<T>::value && std::is_move_constructible<T>::value                            \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_move_assignable;                                      \
-        static constexpr bool is_nothrow_copy_assignable =                                                       \
-            std::is_nothrow_copy_assignable<T>::value                                                            \
-            && std::is_nothrow_copy_constructible<T>::value                                                      \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_nothrow_copy_assignable;                              \
-        static constexpr bool is_nothrow_move_assignable =                                                       \
-            std::is_nothrow_move_assignable<T>::value                                                            \
-            && std::is_nothrow_move_constructible<T>::value                                                      \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_nothrow_move_assignable;                              \
-        static constexpr bool is_swappable =                                                                     \
-            is_swappable_v<T> && std::is_move_constructible<T>::value                                            \
-            && Variant_values_implementation<Is_Trivially_Destructible, Types...>::is_swappable;                 \
-        static constexpr bool is_nothrow_swappable =                                                             \
-            is_nothrow_swappable_v<T> && std::is_nothrow_move_constructible<T>::value                            \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_nothrow_swappable;                                    \
-        static constexpr bool is_equals_comparable =                                                             \
-            Variant_is_equals_comparable<T>::value                                                               \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_equals_comparable;                                    \
-        static constexpr bool is_less_comparable =                                                               \
-            Variant_is_less_comparable<T>::value                                                                 \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_less_comparable;                                      \
-        static constexpr bool is_nothrow_equals_comparable =                                                     \
-            Variant_is_nothrow_equals_comparable<T>::value                                                       \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_nothrow_equals_comparable;                            \
-        static constexpr bool is_nothrow_less_comparable =                                                       \
-            Variant_is_nothrow_less_comparable<T>::value                                                         \
-            && Variant_values_implementation<Is_Trivially_Destructible,                                          \
-                                             Types...>::is_nothrow_less_comparable;                              \
-        template <                                                                                               \
-            typename T2 = T,                                                                                     \
-            typename = typename std::enable_if<std::is_default_constructible<T2>::value>::type>                  \
-        constexpr Variant_values_implementation() noexcept(                                                      \
-            std::is_nothrow_default_constructible<T2>::value)                                                    \
-            : current_value()                                                                                    \
-        {                                                                                                        \
-        }                                                                                                        \
-        template <                                                                                               \
-            typename... Args,                                                                                    \
-            typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>                  \
-        constexpr Variant_values_implementation(in_place_index_t<0>, Args &&... args) noexcept(                  \
-            std::is_nothrow_constructible<T, Args...>::value)                                                    \
-            : current_value(std::forward<Args>(args)...)                                                         \
-        {                                                                                                        \
-        }                                                                                                        \
-        template <std::size_t index,                                                                             \
-                  typename... Args,                                                                              \
-                  typename = typename std::                                                                      \
-                      enable_if<index != 0                                                                       \
-                                && std::                                                                         \
-                                       is_constructible<Variant_values_implementation<Is_Trivially_Destructible, \
-                                                                                      Types...>,                 \
-                                                        in_place_index_t<index - 1>,                             \
-                                                        Args...>::value>::type>                                  \
-        constexpr Variant_values_implementation(in_place_index_t<index>, Args &&... args) noexcept(              \
-            std::is_nothrow_constructible<Variant_values_implementation<Is_Trivially_Destructible,               \
-                                                                        Types...>,                               \
-                                          in_place_index_t<index - 1>,                                           \
-                                          Args...>::value)                                                       \
-            : other_values(in_place_index<index - 1>, std::forward<Args>(args)...)                               \
-        {                                                                                                        \
-        }                                                                                                        \
-        template <                                                                                               \
-            typename U,                                                                                          \
-            typename... Args,                                                                                    \
-            typename = typename std::enable_if<std::is_constructible<T,                                          \
-                                                                     std::initializer_list<U>,                   \
-                                                                     Args...>::value>::type>                     \
-        constexpr Variant_values_implementation(                                                                 \
-            in_place_index_t<0>,                                                                                 \
-            std::initializer_list<U> il,                                                                         \
-            Args &&... args) noexcept(std::is_nothrow_constructible<T,                                           \
-                                                                    std::initializer_list<U>,                    \
-                                                                    Args...>::value)                             \
-            : current_value(il, std::forward<Args>(args)...)                                                     \
-        {                                                                                                        \
-        }                                                                                                        \
-        template <typename U>                                                                                    \
-        static constexpr std::size_t index_from_type() noexcept                                                  \
-        {                                                                                                        \
-            std::size_t next =                                                                                   \
-                Variant_values_implementation<Is_Trivially_Destructible,                                         \
-                                              Types...>::template index_from_type<U>();                          \
-            if(std::is_same<U, T>::value && next == variant_npos)                                                \
-                return 0;                                                                                        \
-            if(next == variant_npos)                                                                             \
-                return variant_npos;                                                                             \
-            return next + 1;                                                                                     \
-        }                                                                                                        \
-        void copy_construct(const Variant_values_implementation &rt,                                             \
-                            std::size_t index) noexcept(is_nothrow_copy_constructible)                           \
-        {                                                                                                        \
-            if(index == 0)                                                                                       \
-                new(const_cast<void *>(static_cast<const volatile void *>(                                       \
-                    std::addressof(current_value)))) T(rt.current_value);                                        \
-            else                                                                                                 \
-                other_values.copy_construct(rt.other_values, index - 1);                                         \
-        }                                                                                                        \
-        void move_construct(Variant_values_implementation &&rt,                                                  \
-                            std::size_t index) noexcept(is_nothrow_move_constructible)                           \
-        {                                                                                                        \
-            if(index == 0)                                                                                       \
-                new(const_cast<void *>(static_cast<const volatile void *>(                                       \
-                    std::addressof(current_value)))) T(std::move(rt.current_value));                             \
-            else                                                                                                 \
-                other_values.move_construct(std::move(rt.other_values), index - 1);                              \
-        }                                                                                                        \
-        void copy_assign(const Variant_values_implementation &rt,                                                \
-                         std::size_t index) noexcept(is_nothrow_copy_assignable)                                 \
-        {                                                                                                        \
-            if(index == 0)                                                                                       \
-                current_value = rt.current_value;                                                                \
-            else                                                                                                 \
-                other_values.copy_assign(rt.other_values, index - 1);                                            \
-        }                                                                                                        \
-        void move_assign(Variant_values_implementation &&rt,                                                     \
-                         std::size_t index) noexcept(is_nothrow_move_assignable)                                 \
-        {                                                                                                        \
-            if(index == 0)                                                                                       \
-                current_value = std::move(rt.current_value);                                                     \
-            else                                                                                                 \
-                other_values.move_assign(std::move(rt.other_values), index - 1);                                 \
-        }                                                                                                        \
-        void destruct(std::size_t index) noexcept                                                                \
-        {                                                                                                        \
-            if(index == 0)                                                                                       \
-                current_value.~T();                                                                              \
-            else                                                                                                 \
-                other_values.destruct(index - 1);                                                                \
-        }                                                                                                        \
-        void swap(Variant_values_implementation &rt,                                                             \
-                  std::size_t index) noexcept(is_nothrow_swappable)                                              \
-        {                                                                                                        \
-            using std::swap;                                                                                     \
-            if(index == 0)                                                                                       \
-                swap(current_value, rt.current_value);                                                           \
-            else                                                                                                 \
-                other_values.swap(rt.other_values, index - 1);                                                   \
-        }                                                                                                        \
-        bool is_equal(const Variant_values_implementation &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_implementation &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);                                            \
-        }                                                                                                        \
-        Destructor                                                                                               \
+#define VULKAN_CPU_UTIL_VARIANT_VALUES(Is_Trivially_Destructible, Destructor)                     \
+    template <typename T, typename... Types>                                                      \
+    union Variant_values_implementation<Is_Trivially_Destructible, T, Types...>                   \
+    {                                                                                             \
+        typedef T Type_0;                                                                         \
+        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 =                                             \
+            std::is_copy_constructible<T>::value                                                  \
+            && Variant_values<Types...>::is_copy_constructible;                                   \
+        static constexpr bool is_move_constructible =                                             \
+            std::is_move_constructible<T>::value                                                  \
+            && Variant_values<Types...>::is_move_constructible;                                   \
+        static constexpr bool is_nothrow_copy_constructible =                                     \
+            std::is_nothrow_copy_constructible<T>::value                                          \
+            && Variant_values<Types...>::is_nothrow_copy_constructible;                           \
+        static constexpr bool is_nothrow_move_constructible =                                     \
+            std::is_nothrow_move_constructible<T>::value                                          \
+            && Variant_values<Types...>::is_nothrow_move_constructible;                           \
+        static constexpr bool is_copy_assignable =                                                \
+            std::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value             \
+            && Variant_values<Types...>::is_copy_assignable;                                      \
+        static constexpr bool is_move_assignable =                                                \
+            std::is_move_assignable<T>::value && std::is_move_constructible<T>::value             \
+            && Variant_values<Types...>::is_move_assignable;                                      \
+        static constexpr bool is_nothrow_copy_assignable =                                        \
+            std::is_nothrow_copy_assignable<T>::value                                             \
+            && std::is_nothrow_copy_constructible<T>::value                                       \
+            && Variant_values<Types...>::is_nothrow_copy_assignable;                              \
+        static constexpr bool is_nothrow_move_assignable =                                        \
+            std::is_nothrow_move_assignable<T>::value                                             \
+            && std::is_nothrow_move_constructible<T>::value                                       \
+            && Variant_values<Types...>::is_nothrow_move_assignable;                              \
+        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>::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_implementation() noexcept(                                       \
+            std::is_nothrow_default_constructible<T2>::value)                                     \
+            : current_value()                                                                     \
+        {                                                                                         \
+        }                                                                                         \
+        template <                                                                                \
+            typename... Args,                                                                     \
+            typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>   \
+        constexpr Variant_values_implementation(in_place_index_t<0>, Args &&... args) noexcept(   \
+            std::is_nothrow_constructible<T, Args...>::value)                                     \
+            : current_value(std::forward<Args>(args)...)                                          \
+        {                                                                                         \
+        }                                                                                         \
+        template <std::size_t index,                                                              \
+                  typename... Args,                                                               \
+                  typename = typename std::                                                       \
+                      enable_if<index != 0 && std::is_constructible<Variant_values<Types...>,     \
+                                                                    in_place_index_t<index - 1>,  \
+                                                                    Args...>::value>::type>       \
+        constexpr Variant_values_implementation(                                                  \
+            in_place_index_t<index>,                                                              \
+            Args &&... args) noexcept(std::is_nothrow_constructible<Variant_values<Types...>,     \
+                                                                    in_place_index_t<index - 1>,  \
+                                                                    Args...>::value)              \
+            : other_values(in_place_index<index - 1>, std::forward<Args>(args)...)                \
+        {                                                                                         \
+        }                                                                                         \
+        template <                                                                                \
+            typename U,                                                                           \
+            typename... Args,                                                                     \
+            typename = typename std::enable_if<std::is_constructible<T,                           \
+                                                                     std::initializer_list<U>,    \
+                                                                     Args...>::value>::type>      \
+        constexpr Variant_values_implementation(                                                  \
+            in_place_index_t<0>,                                                                  \
+            std::initializer_list<U> il,                                                          \
+            Args &&... args) noexcept(std::is_nothrow_constructible<T,                            \
+                                                                    std::initializer_list<U>,     \
+                                                                    Args...>::value)              \
+            : current_value(il, std::forward<Args>(args)...)                                      \
+        {                                                                                         \
+        }                                                                                         \
+        template <typename U>                                                                     \
+        static constexpr std::size_t index_from_type() noexcept                                   \
+        {                                                                                         \
+            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)                                                              \
+                return variant_npos;                                                              \
+            return next + 1;                                                                      \
+        }                                                                                         \
+        void copy_construct(const Variant_values_implementation &rt,                              \
+                            std::size_t index) noexcept(is_nothrow_copy_constructible)            \
+        {                                                                                         \
+            if(index == 0)                                                                        \
+                new(const_cast<void *>(static_cast<const volatile void *>(                        \
+                    std::addressof(current_value)))) T(rt.current_value);                         \
+            else                                                                                  \
+                other_values.copy_construct(rt.other_values, index - 1);                          \
+        }                                                                                         \
+        void move_construct(Variant_values_implementation &&rt,                                   \
+                            std::size_t index) noexcept(is_nothrow_move_constructible)            \
+        {                                                                                         \
+            if(index == 0)                                                                        \
+                new(const_cast<void *>(static_cast<const volatile void *>(                        \
+                    std::addressof(current_value)))) T(std::move(rt.current_value));              \
+            else                                                                                  \
+                other_values.move_construct(std::move(rt.other_values), index - 1);               \
+        }                                                                                         \
+        void copy_assign(const Variant_values_implementation &rt,                                 \
+                         std::size_t index) noexcept(is_nothrow_copy_assignable)                  \
+        {                                                                                         \
+            if(index == 0)                                                                        \
+                current_value = rt.current_value;                                                 \
+            else                                                                                  \
+                other_values.copy_assign(rt.other_values, index - 1);                             \
+        }                                                                                         \
+        void move_assign(Variant_values_implementation &&rt,                                      \
+                         std::size_t index) noexcept(is_nothrow_move_assignable)                  \
+        {                                                                                         \
+            if(index == 0)                                                                        \
+                current_value = std::move(rt.current_value);                                      \
+            else                                                                                  \
+                other_values.move_assign(std::move(rt.other_values), index - 1);                  \
+        }                                                                                         \
+        void destruct(std::size_t index) noexcept                                                 \
+        {                                                                                         \
+            if(index == 0)                                                                        \
+                current_value.~T();                                                               \
+            else                                                                                  \
+                other_values.destruct(index - 1);                                                 \
+        }                                                                                         \
+        void swap(Variant_values_implementation &rt,                                              \
+                  std::size_t index) noexcept(is_nothrow_swappable)                               \
+        {                                                                                         \
+            using std::swap;                                                                      \
+            if(index == 0)                                                                        \
+                swap(current_value, rt.current_value);                                            \
+            else                                                                                  \
+                other_values.swap(rt.other_values, index - 1);                                    \
+        }                                                                                         \
+        bool is_equal(const Variant_values_implementation &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_implementation &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);                             \
+        }                                                                                         \
+        Destructor                                                                                \
     };
 
 VULKAN_CPU_UTIL_VARIANT_VALUES(true, ~Variant_values_implementation() = default;)
@@ -516,6 +497,27 @@ VULKAN_CPU_UTIL_VARIANT_VALUES(false, ~Variant_values_implementation(){})
 template <std::size_t Index, typename... Types>
 struct Variant_get;
 
+template <typename T, typename... Types>
+struct Variant_get<0, T, Types...>
+{
+    static constexpr const T &get(const Variant_values<T, Types...> &values) noexcept
+    {
+        return values.current_value;
+    }
+    static constexpr T &get(Variant_values<T, Types...> &values) noexcept
+    {
+        return values.current_value;
+    }
+    static constexpr const T &&get(const Variant_values<T, Types...> &&values) noexcept
+    {
+        return std::move(values.current_value);
+    }
+    static constexpr T &&get(Variant_values<T, Types...> &&values) noexcept
+    {
+        return std::move(values.current_value);
+    }
+};
+
 template <std::size_t Index, typename T, typename... Types>
 struct Variant_get<Index, T, Types...>
 {
@@ -541,27 +543,6 @@ struct Variant_get<Index, T, Types...>
     }
 };
 
-template <typename T, typename... Types>
-struct Variant_get<0, T, Types...>
-{
-    static constexpr const T &get(const Variant_values<T, Types...> &values) noexcept
-    {
-        return values.current_value;
-    }
-    static constexpr T &get(Variant_values<T, Types...> &values) noexcept
-    {
-        return values.current_value;
-    }
-    static constexpr const T &&get(const Variant_values<T, Types...> &&values) noexcept
-    {
-        return std::move(values.current_value);
-    }
-    static constexpr T &&get(Variant_values<T, Types...> &&values) noexcept
-    {
-        return std::move(values.current_value);
-    }
-};
-
 #define VULKAN_CPU_UTIL_VARIANT_DISPATCH(Const, Ref)                                               \
     template <std::size_t Index,                                                                   \
               typename Return_Type,                                                                \