From acb72bf848cd07e3d65c802a42aeb32590e96814 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 22 Jun 2017 01:29:02 -0700 Subject: [PATCH] generate_spirv_parser is complete, commit everything I missed last time --- CMakeLists.txt | 2 +- src/generate_spirv_parser/ast.h | 42 ++ src/generate_spirv_parser/generate.cpp | 137 +++--- src/generate_spirv_parser/generate.h | 12 +- .../generate_spirv_parser.cpp | 2 - src/generate_spirv_parser/parser.cpp | 7 +- src/generate_spirv_parser/patch.cpp | 89 ++++ src/generate_spirv_parser/patch.h | 66 +++ src/util/variant.h | 415 +++++++++--------- 9 files changed, 488 insertions(+), 284 deletions(-) create mode 100644 src/generate_spirv_parser/patch.cpp create mode 100644 src/generate_spirv_parser/patch.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e9ef5d7..6890d6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/generate_spirv_parser/ast.h b/src/generate_spirv_parser/ast.h index d3fdefa..e664051 100644 --- a/src/generate_spirv_parser/ast.h +++ b/src/generate_spirv_parser/ast.h @@ -25,6 +25,8 @@ #define GENERATE_SPIRV_PARSER_AST_H_ #include "json/json.h" +#include "util/optional.h" +#include "util/string_view.h" #include #include #include @@ -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 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 diff --git a/src/generate_spirv_parser/generate.cpp b/src/generate_spirv_parser/generate.cpp index ff26f95..7a07d35 100644 --- a/src/generate_spirv_parser/generate.cpp +++ b/src/generate_spirv_parser/generate.cpp @@ -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(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"; - 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 &>::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(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(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 &>::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(value)); +else +`os << get_enumerant_name(value); +)"); + break; } break; } diff --git a/src/generate_spirv_parser/generate.h b/src/generate_spirv_parser/generate.h index 4cfc4f6..b873b22 100644 --- a/src/generate_spirv_parser/generate.h +++ b/src/generate_spirv_parser/generate.h @@ -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 ¶meter); + const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter + ¶meter); + 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; diff --git a/src/generate_spirv_parser/generate_spirv_parser.cpp b/src/generate_spirv_parser/generate_spirv_parser.cpp index 8888aa9..c03e25d 100644 --- a/src/generate_spirv_parser/generate_spirv_parser.cpp +++ b/src/generate_spirv_parser/generate_spirv_parser.cpp @@ -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) diff --git a/src/generate_spirv_parser/parser.cpp b/src/generate_spirv_parser/parser.cpp index d1bd543..f7f7c76 100644 --- a/src/generate_spirv_parser/parser.cpp +++ b/src/generate_spirv_parser/parser.cpp @@ -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 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 index 0000000..8eb062e --- /dev/null +++ b/src/generate_spirv_parser/patch.cpp @@ -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(&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 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 index 0000000..eb253ae --- /dev/null +++ b/src/generate_spirv_parser/patch.h @@ -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 +#include + +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 get_patches(); +}; +} +} + +#endif /* GENERATE_SPIRV_PARSER_PATCH_H_ */ diff --git a/src/util/variant.h b/src/util/variant.h index da5ae14..288ac14 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -244,7 +244,7 @@ template constexpr bool variant_is_trivially_destructible() noexcept { bool values[] = { - std::is_trivially_destructible::value..., + true, std::is_trivially_destructible::value..., }; for(bool v : values) if(!v) @@ -312,201 +312,182 @@ template using Variant_values = Variant_values_implementation(), Types...>; -#define VULKAN_CPU_UTIL_VARIANT_VALUES(Is_Trivially_Destructible, Destructor) \ - template \ - union Variant_values_implementation \ - { \ - typedef T Type_0; \ - static_assert(!std::is_void::value, "invalid variant member type"); \ - static_assert(!std::is_reference::value, "invalid variant member type"); \ - static_assert(!std::is_array::value, "invalid variant member type"); \ - static_assert(!std::is_const::value, "invalid variant member type"); \ - static_assert(!std::is_volatile::value, "invalid variant member type"); \ - static_assert(std::is_object::value, "invalid variant member type"); \ - T current_value; \ - Variant_values_implementation other_values; \ - static constexpr bool is_copy_constructible = \ - std::is_copy_constructible::value \ - && Variant_values_implementation::is_copy_constructible; \ - static constexpr bool is_move_constructible = \ - std::is_move_constructible::value \ - && Variant_values_implementation::is_move_constructible; \ - static constexpr bool is_nothrow_copy_constructible = \ - std::is_nothrow_copy_constructible::value \ - && Variant_values_implementation::is_nothrow_copy_constructible; \ - static constexpr bool is_nothrow_move_constructible = \ - std::is_nothrow_move_constructible::value \ - && Variant_values_implementation::is_nothrow_move_constructible; \ - static constexpr bool is_copy_assignable = \ - std::is_copy_assignable::value && std::is_copy_constructible::value \ - && Variant_values_implementation::is_copy_assignable; \ - static constexpr bool is_move_assignable = \ - std::is_move_assignable::value && std::is_move_constructible::value \ - && Variant_values_implementation::is_move_assignable; \ - static constexpr bool is_nothrow_copy_assignable = \ - std::is_nothrow_copy_assignable::value \ - && std::is_nothrow_copy_constructible::value \ - && Variant_values_implementation::is_nothrow_copy_assignable; \ - static constexpr bool is_nothrow_move_assignable = \ - std::is_nothrow_move_assignable::value \ - && std::is_nothrow_move_constructible::value \ - && Variant_values_implementation::is_nothrow_move_assignable; \ - static constexpr bool is_swappable = \ - is_swappable_v && std::is_move_constructible::value \ - && Variant_values_implementation::is_swappable; \ - static constexpr bool is_nothrow_swappable = \ - is_nothrow_swappable_v && std::is_nothrow_move_constructible::value \ - && Variant_values_implementation::is_nothrow_swappable; \ - static constexpr bool is_equals_comparable = \ - Variant_is_equals_comparable::value \ - && Variant_values_implementation::is_equals_comparable; \ - static constexpr bool is_less_comparable = \ - Variant_is_less_comparable::value \ - && Variant_values_implementation::is_less_comparable; \ - static constexpr bool is_nothrow_equals_comparable = \ - Variant_is_nothrow_equals_comparable::value \ - && Variant_values_implementation::is_nothrow_equals_comparable; \ - static constexpr bool is_nothrow_less_comparable = \ - Variant_is_nothrow_less_comparable::value \ - && Variant_values_implementation::is_nothrow_less_comparable; \ - template < \ - typename T2 = T, \ - typename = typename std::enable_if::value>::type> \ - constexpr Variant_values_implementation() noexcept( \ - std::is_nothrow_default_constructible::value) \ - : current_value() \ - { \ - } \ - template < \ - typename... Args, \ - typename = typename std::enable_if::value>::type> \ - constexpr Variant_values_implementation(in_place_index_t<0>, Args &&... args) noexcept( \ - std::is_nothrow_constructible::value) \ - : current_value(std::forward(args)...) \ - { \ - } \ - template , \ - in_place_index_t, \ - Args...>::value>::type> \ - constexpr Variant_values_implementation(in_place_index_t, Args &&... args) noexcept( \ - std::is_nothrow_constructible, \ - in_place_index_t, \ - Args...>::value) \ - : other_values(in_place_index, std::forward(args)...) \ - { \ - } \ - template < \ - typename U, \ - typename... Args, \ - typename = typename std::enable_if, \ - Args...>::value>::type> \ - constexpr Variant_values_implementation( \ - in_place_index_t<0>, \ - std::initializer_list il, \ - Args &&... args) noexcept(std::is_nothrow_constructible, \ - Args...>::value) \ - : current_value(il, std::forward(args)...) \ - { \ - } \ - template \ - static constexpr std::size_t index_from_type() noexcept \ - { \ - std::size_t next = \ - Variant_values_implementation::template index_from_type(); \ - if(std::is_same::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(static_cast( \ - 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(static_cast( \ - 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(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(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 \ + union Variant_values_implementation \ + { \ + typedef T Type_0; \ + static_assert(!std::is_void::value, "invalid variant member type"); \ + static_assert(!std::is_reference::value, "invalid variant member type"); \ + static_assert(!std::is_array::value, "invalid variant member type"); \ + static_assert(!std::is_const::value, "invalid variant member type"); \ + static_assert(!std::is_volatile::value, "invalid variant member type"); \ + static_assert(std::is_object::value, "invalid variant member type"); \ + T current_value; \ + Variant_values other_values; \ + static constexpr bool is_copy_constructible = \ + std::is_copy_constructible::value \ + && Variant_values::is_copy_constructible; \ + static constexpr bool is_move_constructible = \ + std::is_move_constructible::value \ + && Variant_values::is_move_constructible; \ + static constexpr bool is_nothrow_copy_constructible = \ + std::is_nothrow_copy_constructible::value \ + && Variant_values::is_nothrow_copy_constructible; \ + static constexpr bool is_nothrow_move_constructible = \ + std::is_nothrow_move_constructible::value \ + && Variant_values::is_nothrow_move_constructible; \ + static constexpr bool is_copy_assignable = \ + std::is_copy_assignable::value && std::is_copy_constructible::value \ + && Variant_values::is_copy_assignable; \ + static constexpr bool is_move_assignable = \ + std::is_move_assignable::value && std::is_move_constructible::value \ + && Variant_values::is_move_assignable; \ + static constexpr bool is_nothrow_copy_assignable = \ + std::is_nothrow_copy_assignable::value \ + && std::is_nothrow_copy_constructible::value \ + && Variant_values::is_nothrow_copy_assignable; \ + static constexpr bool is_nothrow_move_assignable = \ + std::is_nothrow_move_assignable::value \ + && std::is_nothrow_move_constructible::value \ + && Variant_values::is_nothrow_move_assignable; \ + static constexpr bool is_swappable = \ + is_swappable_v && std::is_move_constructible::value \ + && Variant_values::is_swappable; \ + static constexpr bool is_nothrow_swappable = \ + is_nothrow_swappable_v && std::is_nothrow_move_constructible::value \ + && Variant_values::is_nothrow_swappable; \ + static constexpr bool is_equals_comparable = \ + Variant_is_equals_comparable::value \ + && Variant_values::is_equals_comparable; \ + static constexpr bool is_less_comparable = \ + Variant_is_less_comparable::value && Variant_values::is_less_comparable; \ + static constexpr bool is_nothrow_equals_comparable = \ + Variant_is_nothrow_equals_comparable::value \ + && Variant_values::is_nothrow_equals_comparable; \ + static constexpr bool is_nothrow_less_comparable = \ + Variant_is_nothrow_less_comparable::value \ + && Variant_values::is_nothrow_less_comparable; \ + template < \ + typename T2 = T, \ + typename = typename std::enable_if::value>::type> \ + constexpr Variant_values_implementation() noexcept( \ + std::is_nothrow_default_constructible::value) \ + : current_value() \ + { \ + } \ + template < \ + typename... Args, \ + typename = typename std::enable_if::value>::type> \ + constexpr Variant_values_implementation(in_place_index_t<0>, Args &&... args) noexcept( \ + std::is_nothrow_constructible::value) \ + : current_value(std::forward(args)...) \ + { \ + } \ + template , \ + in_place_index_t, \ + Args...>::value>::type> \ + constexpr Variant_values_implementation( \ + in_place_index_t, \ + Args &&... args) noexcept(std::is_nothrow_constructible, \ + in_place_index_t, \ + Args...>::value) \ + : other_values(in_place_index, std::forward(args)...) \ + { \ + } \ + template < \ + typename U, \ + typename... Args, \ + typename = typename std::enable_if, \ + Args...>::value>::type> \ + constexpr Variant_values_implementation( \ + in_place_index_t<0>, \ + std::initializer_list il, \ + Args &&... args) noexcept(std::is_nothrow_constructible, \ + Args...>::value) \ + : current_value(il, std::forward(args)...) \ + { \ + } \ + template \ + static constexpr std::size_t index_from_type() noexcept \ + { \ + std::size_t next = Variant_values::template index_from_type(); \ + if(std::is_same::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(static_cast( \ + 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(static_cast( \ + 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(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(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 struct Variant_get; +template +struct Variant_get<0, T, Types...> +{ + static constexpr const T &get(const Variant_values &values) noexcept + { + return values.current_value; + } + static constexpr T &get(Variant_values &values) noexcept + { + return values.current_value; + } + static constexpr const T &&get(const Variant_values &&values) noexcept + { + return std::move(values.current_value); + } + static constexpr T &&get(Variant_values &&values) noexcept + { + return std::move(values.current_value); + } +}; + template struct Variant_get { @@ -541,27 +543,6 @@ struct Variant_get } }; -template -struct Variant_get<0, T, Types...> -{ - static constexpr const T &get(const Variant_values &values) noexcept - { - return values.current_value; - } - static constexpr T &get(Variant_values &values) noexcept - { - return values.current_value; - } - static constexpr const T &&get(const Variant_values &&values) noexcept - { - return std::move(values.current_value); - } - static constexpr T &&get(Variant_values &&values) noexcept - { - return std::move(values.current_value); - } -}; - #define VULKAN_CPU_UTIL_VARIANT_DISPATCH(Const, Ref) \ template