generate_spirv_parser generates dependencies for enum values in spirv.h
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 15 Jun 2017 04:47:23 +0000 (21:47 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 15 Jun 2017 04:47:23 +0000 (21:47 -0700)
src/generate_spirv_parser/generate.cpp
src/generate_spirv_parser/generate.h
src/util/enum.h

index 9d1f8f7c349cf8cc3cde9b07f9f4c2149d0e46d1..115e2372deff73f4dee3d7228271512049fa202b 100644 (file)
@@ -52,6 +52,8 @@ constexpr Generator::Indent_t Generator::indent;
 constexpr const char *Generator::vulkan_cpu_namespace_name;
 constexpr const char *Generator::spirv_namespace_name;
 constexpr const char *Generator::spirv_namespace_names[];
+constexpr const char *Generator::extension_enum_name;
+constexpr const char *Generator::capability_enum_name;
 
 std::string Generator::get_guard_macro_name_from_file_name(std::string file_name)
 {
@@ -88,6 +90,35 @@ std::string Generator::get_guard_macro_name_from_file_name(std::string file_name
     return retval;
 }
 
+namespace
+{
+constexpr bool is_identifier_start(char ch) noexcept
+{
+    if(ch >= 'A' && ch <= 'Z')
+        return true;
+    if(ch >= 'a' && ch <= 'z')
+        return true;
+    return ch == '_';
+}
+}
+
+std::string Generator::get_enumerant_name(const char *enumeration_name,
+                                          std::size_t enumeration_name_size,
+                                          std::string enumerant_name)
+{
+    bool need_prefix;
+    if(enumerant_name.compare(0, enumeration_name_size, enumeration_name, enumeration_name_size)
+       == 0)
+        need_prefix = true; // ensure that we don't end up with name collisions
+    else if(enumerant_name.empty())
+        need_prefix = true; // return something other than the empty string
+    else
+        need_prefix = !is_identifier_start(enumerant_name[0]);
+    if(need_prefix)
+        return std::move(enumerant_name.insert(0, enumeration_name, enumeration_name_size));
+    return enumerant_name;
+}
+
 void Generator::write_indent(Generator_state &state)
 {
     static constexpr auto indent_string = "    ";
@@ -221,6 +252,33 @@ std::unordered_set<std::string> Generator::get_extensions(const ast::Top_level &
     return retval;
 }
 
+void Generator::write_capabilities_set(Generator_state &state,
+                                       const ast::Capabilities &capabilities)
+{
+    state << "util::Enum_set<" << capability_enum_name << ">{";
+    auto separator = "";
+    for(auto &capability : capabilities.capabilities)
+    {
+        state << separator << capability_enum_name
+              << "::" << get_enumerant_name(capability_enum_name, capability);
+        separator = ", ";
+    }
+    state << "}";
+}
+
+void Generator::write_extensions_set(Generator_state &state, const ast::Extensions &extensions)
+{
+    state << "util::Enum_set<" << extension_enum_name << ">{";
+    auto separator = "";
+    for(auto &extension : extensions.extensions)
+    {
+        state << separator << extension_enum_name
+              << "::" << get_enumerant_name(extension_enum_name, extension);
+        separator = ", ";
+    }
+    state << "}";
+}
+
 struct Spirv_header_generator final : public Generator
 {
     Spirv_header_generator() : Generator("spirv.h")
@@ -233,7 +291,7 @@ struct Spirv_header_generator final : public Generator
     };
     static Enum_priority get_enum_priority(const std::string &enum_name) noexcept
     {
-        if(enum_name == "Capability")
+        if(enum_name == capability_enum_name)
             return Enum_priority::capability;
         return Enum_priority::default_priority;
     }
@@ -254,7 +312,7 @@ struct Spirv_header_generator final : public Generator
         write_file_comments(state, top_level.copyright);
         write_file_guard_start(state);
         state << "#include <cstdint>\n"
-                 "#include \"util/bitset.h\"\n";
+                 "#include \"util/enum.h\"\n";
         state << "\n";
         write_namespaces_start(state, spirv_namespace_names);
         state << "typedef std::uint32_t Word;\n";
@@ -273,27 +331,36 @@ struct Spirv_header_generator final : public Generator
             extensions_list.push_back(extension);
         std::sort(extensions_list.begin(), extensions_list.end());
         state << "\n"
-                 "enum class Extension : std::size_t\n"
-                 "{\n";
+                 "enum class "
+              << extension_enum_name << " : std::size_t\n"
+                                        "{\n";
         {
             auto push_indent = state.pushed_indent();
             for(auto &extension : extensions_list)
-                state << indent << extension << ",\n";
+                state << indent << get_enumerant_name(extension_enum_name, extension) << ",\n";
         }
         state << "};\n"
                  "\n"
-                 "constexpr std::size_t Extension_count = "
-              << unsigned_dec_integer_literal(extensions_list.size())
-              << ";\n"
-                 "\n"
-                 "constexpr const char *get_extension_name(Extension extension) noexcept\n"
-                 "{\n";
+                 "vulkan_cpu_util_generate_enum_traits("
+              << extension_enum_name;
         {
             auto push_indent = state.pushed_indent();
-            state << indent << "switch(extension)\n" << indent << "{\n";
+            for(auto &extension : extensions_list)
+                state << ",\n" << indent << extension_enum_name
+                      << "::" << get_enumerant_name(extension_enum_name, extension);
+            state << ");\n";
+        }
+        state << "\n"
+                 "constexpr const char *get_enumerant_name("
+              << extension_enum_name << " v) noexcept\n"
+                                        "{\n";
+        {
+            auto push_indent = state.pushed_indent();
+            state << indent << "switch(v)\n" << indent << "{\n";
             for(auto &extension : extensions_list)
             {
-                state << indent << "case Extension::" << extension << ":\n";
+                state << indent << "case " << extension_enum_name
+                      << "::" << get_enumerant_name(extension_enum_name, extension) << ":\n";
                 auto push_indent2 = state.pushed_indent();
                 state << indent << "return \"" << extension << "\";\n";
             }
@@ -316,25 +383,98 @@ struct Spirv_header_generator final : public Generator
             if(util::holds_alternative<ast::Operand_kinds::Operand_kind::Enumerants>(
                    operand_kind->value))
             {
+                bool is_bit_enum =
+                    operand_kind->category == ast::Operand_kinds::Operand_kind::Category::bit_enum;
                 auto &enumerants =
                     util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind->value);
                 state << "\n"
                          "enum class "
                       << operand_kind->kind << " : Word\n"
                                                "{\n";
-                auto push_indent = state.pushed_indent();
-                for(auto &enumerant : enumerants.enumerants)
                 {
-                    state << indent << enumerant.enumerant << " = ";
-                    if(operand_kind->category
-                       == ast::Operand_kinds::Operand_kind::Category::bit_enum)
-                        state << unsigned_hex_integer_literal(enumerant.value);
-                    else
-                        state << unsigned_dec_integer_literal(enumerant.value);
-                    state << ",\n";
+                    auto push_indent = state.pushed_indent();
+                    for(auto &enumerant : enumerants.enumerants)
+                    {
+                        state << indent
+                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                              << " = ";
+                        if(is_bit_enum)
+                            state << unsigned_hex_integer_literal(enumerant.value);
+                        else
+                            state << unsigned_dec_integer_literal(enumerant.value);
+                        state << ",\n";
+                    }
                 }
-                push_indent.finish();
                 state << "};\n";
+                if(!is_bit_enum)
+                {
+                    state << "\n"
+                             "vulkan_cpu_util_generate_enum_traits("
+                          << operand_kind->kind;
+                    {
+                        auto push_indent = state.pushed_indent();
+                        for(auto &enumerant : enumerants.enumerants)
+                            state << ",\n" << indent << operand_kind->kind << "::"
+                                  << get_enumerant_name(operand_kind->kind, enumerant.enumerant);
+                        state << ");\n";
+                    }
+                }
+                state << "\n"
+                         "constexpr const char *get_enumerant_name("
+                      << operand_kind->kind << " v) noexcept\n"
+                                               "{\n";
+                {
+                    auto push_indent = state.pushed_indent();
+                    state << indent << "switch(v)\n" << indent << "{\n";
+                    for(auto &enumerant : enumerants.enumerants)
+                    {
+                        state << indent << "case " << operand_kind->kind
+                              << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                              << ":\n";
+                        auto push_indent2 = state.pushed_indent();
+                        state << indent << "return \"" << enumerant.enumerant << "\";\n";
+                    }
+                    state << indent << "}\n" << indent << "return \"\";\n";
+                }
+                state << "}\n"
+                         "\n"
+                         "constexpr util::Enum_set<"
+                      << capability_enum_name << "> get_directly_required_capability_set("
+                      << operand_kind->kind << " v) noexcept\n"
+                                               "{\n";
+                {
+                    auto push_indent = state.pushed_indent();
+                    state << indent << "switch(v)\n" << indent << "{\n";
+                    for(auto &enumerant : enumerants.enumerants)
+                    {
+                        state << indent << "case " << operand_kind->kind
+                              << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                              << ":\n";
+                        auto push_indent2 = state.pushed_indent();
+                        state << indent << "return " << enumerant.capabilities << ";\n";
+                    }
+                    state << indent << "}\n" << indent << "return {};\n";
+                }
+                state << "}\n"
+                         "\n"
+                         "constexpr util::Enum_set<"
+                      << extension_enum_name << "> get_directly_required_extension_set("
+                      << operand_kind->kind << " v) noexcept\n"
+                                               "{\n";
+                {
+                    auto push_indent = state.pushed_indent();
+                    state << indent << "switch(v)\n" << indent << "{\n";
+                    for(auto &enumerant : enumerants.enumerants)
+                    {
+                        state << indent << "case " << operand_kind->kind
+                              << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                              << ":\n";
+                        auto push_indent2 = state.pushed_indent();
+                        state << indent << "return " << enumerant.extensions << ";\n";
+                    }
+                    state << indent << "}\n" << indent << "return {};\n";
+                }
+                state << "}\n";
             }
         }
 
index 50c816acc51002dde46179610fc76da45358a570..908050c48101202a67c2f745cbf8041d50945aae 100644 (file)
@@ -72,6 +72,16 @@ protected:
             os << std::forward<T>(v);
             return *this;
         }
+        Generator_state &operator<<(const ast::Capabilities &v)
+        {
+            write_capabilities_set(*this, v);
+            return *this;
+        }
+        Generator_state &operator<<(const ast::Extensions &v)
+        {
+            write_extensions_set(*this, v);
+            return *this;
+        }
         Push_indent pushed_indent() noexcept;
     };
     class Push_indent final
@@ -175,6 +185,21 @@ protected:
 
 protected:
     static std::string get_guard_macro_name_from_file_name(std::string file_name);
+    static std::string get_enumerant_name(const std::string &enumeration_name,
+                                          std::string enumerant_name)
+    {
+        return get_enumerant_name(
+            enumeration_name.data(), enumeration_name.size(), std::move(enumerant_name));
+    }
+    static std::string get_enumerant_name(const char *enumeration_name, std::string enumerant_name)
+    {
+        return get_enumerant_name(enumeration_name,
+                                  std::char_traits<char>::length(enumeration_name),
+                                  std::move(enumerant_name));
+    }
+    static std::string get_enumerant_name(const char *enumeration_name,
+                                          std::size_t enumeration_name_size,
+                                          std::string enumerant_name);
     static void write_indent(Generator_state &state);
     static void write_automatically_generated_file_warning(Generator_state &state);
     static void write_copyright_comment(Generator_state &state, const ast::Copyright &copyright);
@@ -271,6 +296,9 @@ private:
 
 protected:
     static std::unordered_set<std::string> get_extensions(const ast::Top_level &top_level);
+    static void write_capabilities_set(Generator_state &state,
+                                       const ast::Capabilities &capabilities);
+    static void write_extensions_set(Generator_state &state, const ast::Extensions &extensions);
 
 protected:
     static constexpr const char *vulkan_cpu_namespace_name = "vulkan_cpu";
@@ -278,6 +306,8 @@ protected:
     static constexpr const char *spirv_namespace_names[] = {
         vulkan_cpu_namespace_name, spirv_namespace_name,
     };
+    static constexpr const char *capability_enum_name = "Capability";
+    static constexpr const char *extension_enum_name = "Extension";
 
 public:
     explicit Generator(const char *output_base_file_name) noexcept
@@ -309,4 +339,4 @@ struct Generators
 }
 }
 
-#endif /* GENERATE_SPIRV_PARSER_GENERATE_H_ */
\ No newline at end of file
+#endif /* GENERATE_SPIRV_PARSER_GENERATE_H_ */
index 13f96afc1d37a06c72e2d3b06b1614af91217098..e063a9ef81c5c5406fccd325535c1ae9bbda2fb0 100644 (file)
@@ -190,8 +190,11 @@ struct Default_enum_traits
 
 template <typename Enum, Enum... Values>
 static constexpr Enum_values<Enum, sizeof...(Values)> Default_enum_traits<Enum, Values...>::values;
+/** generate code for Enum_traits instantiation; use like
+ * <code>vulkan_cpu_util_generate_enum_traits(Enum, Enum::Value1, Enum::Value2, Enum::Value3,
+ * <...>);</code> */
 #define vulkan_cpu_util_generate_enum_traits(...) \
-    ::vulkan_cpu::util::detail::Default_enum_traits<__VA_ARGS__> enum_traits_resolve_function(Enum);
+    ::vulkan_cpu::util::detail::Default_enum_traits<__VA_ARGS__> enum_traits_resolve_function(Enum)
 }
 
 /** behaves like a std::set<T> */