layers: Refactored pNext chain walks to template

The while loops for the walking the pNext chains were implemented by
repeated code. These were refactored into a common template.  Added
autogenerated 'traits' objects for the pNext linked structs.

Delete cut and paste duplicate pNext chain walk.

Change-Id: I46457bb5432219c74f9356e5230c70e4a9ef16df
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index 3d4ef46..a8e9f13 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -130,6 +130,7 @@
         copyright += ' * Author: Courtney Goeltzenleuchter <courtneygo@google.com>\n'
         copyright += ' * Author: Tobin Ehlis <tobine@google.com>\n'
         copyright += ' * Author: Chris Forbes <chrisforbes@google.com>\n'
+        copyright += ' * Author: John Zulauf<jzulauf@lunarg.com>\n'
         copyright += ' *\n'
         copyright += ' ****************************************************************************/\n'
         write(copyright, file=self.outFile)
@@ -919,6 +920,112 @@
                 safe_struct_body.append("#endif // %s\n" % item.ifdef_protect)
         return "\n".join(safe_struct_body)
     #
+    # Generate the type map
+    def GenerateTypeMapHelperHeader(self):
+        prefix = 'Lvl'
+        fprefix = 'lvl_'
+        typemap = prefix + 'TypeMap'
+        idmap = prefix + 'STypeMap'
+        name_member = 'kName'
+        type_member = 'Type'
+        id_member = 'kSType'
+        decl_prefix ='constexpr static'
+        char_decl = decl_prefix + ' const char *'
+        id_decl = decl_prefix + ' const VkStructureType '
+        generic_header = prefix + 'GenericHeader'
+        typename_func = fprefix + 'typename'
+        idname_func = fprefix + 'stype_name'
+        find_func = fprefix + 'find_in_chain'
+
+        explanatory_comment = '\n'.join((
+                '// These empty generic templates are specialized for each type with sType',
+                '// members and for each sType -- providing a two way map between structure',
+                '// types and sTypes as well as a kName stringification for convenience'))
+
+        empty_typemap = 'template <typename T> struct ' + typemap + ' {};'
+        typemap_format  = 'template <> struct {template}<{typename}> {{\n'
+        typemap_format += '    {char_decl}{name} = "{typename}";\n'
+        typemap_format += '    {id_decl}{id_member} = {id_value};\n'
+        typemap_format += '}};\n'
+
+        empty_idmap = 'template <VkStructureType id> struct ' + idmap + ' {};'
+        idmap_format = ''.join((
+            'template <> struct {template}<{id_value}> {{\n',
+            '    typedef {typename} {typedef};\n',
+            '    {char_decl}{name} = "{id_value}";\n',
+            '}};\n'))
+
+        # Define the utilities (here so any renaming stays consistent), if this grows large, refactor to a fixed .h file
+        utilities_format = '\n'.join((
+            '// Header "base class" for pNext chain traversal',
+            'struct {header} {{',
+            '   VkStructureType sType;',
+            '   const {header} *pNext;',
+            '}};',
+            '',
+            '// Find an entry of the given type in the pNext chain',
+            'template <typename T> const T *{find_func}(const void *next) {{',
+            '    const {header} *current = reinterpret_cast<const {header} *>(next);',
+            '    const T *found = nullptr;',
+            '    while (current) {{',
+            '        if ({type_map}<T>::{id_member} == current->sType) {{',
+            '            found = reinterpret_cast<const T*>(current);',
+            '            current = nullptr;',
+            '        }} else {{',
+            '            current = current->pNext;',
+            '        }}',
+            '    }}',
+            '    return found;',
+            '}}',
+            '',
+            '// Convenience functions for accessing the other mapped objects name field',
+            'template <typename T> constexpr const char *{idname_func}() {{',
+            '    return {id_map}<{type_map}<T>::{id_member}>::{name_member};',
+            '}}',
+            'template <VkStructureType s_type> constexpr const char *{typename_func}() {{',
+            '    return {type_map}<typename {id_map}<s_type>::{type_member}>::{name_member};',
+            '}}'))
+
+        code = []
+        code.append('\n'.join((
+            '#pragma once',
+            '#include <vulkan/vulkan.h>\n',
+            explanatory_comment, '',
+            empty_idmap,
+            empty_typemap, '',
+            utilities_format.format(name_member=name_member, id_member=id_member, id_map=idmap, type_map=typemap,
+                type_member=type_member, header=generic_header, typename_func=typename_func, idname_func=idname_func,
+                find_func=find_func), ''
+            )))
+
+        # Generate the specializations for each type and stype
+
+        for item in self.structMembers:
+            typename = item.name
+            info = self.structTypes.get(typename)
+            if not info:
+                continue
+
+            if item.ifdef_protect != None:
+                code.append('#ifdef %s' % item.ifdef_protect)
+
+            code.append('// Map type {} to id {}'.format(typename, info.value))
+            code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value,
+                char_decl=char_decl, id_decl=id_decl, name=name_member, id_member=id_member))
+            code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, char_decl=char_decl, typedef=type_member, name=name_member))
+
+            if item.ifdef_protect != None:
+                code.append('#endif // %s' % item.ifdef_protect)
+
+        #for typename, info in self.structTypes.items():
+        #    code.append("// Map type {} to id {}".format(typename, info.value))
+        #    code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value,
+        #        char_decl=char_decl, id_decl=id_decl, name=name_member, id_member=id_member))
+        #    code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, char_decl=char_decl, typedef=type_member, name=name_member))
+
+        return "\n".join(code)
+
+    #
     # Create a helper file and return it as a string
     def OutputDestFile(self):
         if self.helper_file_type == 'enum_string_header':
@@ -935,6 +1042,8 @@
             return self.GenerateObjectTypesHelperHeader()
         elif self.helper_file_type == 'extension_helper_header':
             return self.GenerateExtensionHelperHeader()
+        elif self.helper_file_type == 'typemap_helper_header':
+            return self.GenerateTypeMapHelperHeader()
         else:
             return 'Bad Helper File Generator Option %s' % self.helper_file_type