• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright(c) 2015-2020, NVIDIA CORPORATION. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // Modifications Copyright (C) 2023 The Android Open Source Project
16 //   * Updated RAII to work with VULKAN_HPP_NO_EXCEPTIONS.
17 
18 #include "VulkanHppGenerator.hpp"
19 
20 #include <algorithm>
21 #include <cassert>
22 #include <fstream>
23 #include <regex>
24 #include <sstream>
25 
26 // Uncomment to generate function definitions with cpp comment saying
27 // which function generated it.
28 //#define DEBUG_GENERATOR 1
29 
30 void                                checkAttributes( int                                                  line,
31                                                      std::map<std::string, std::string> const &           attributes,
32                                                      std::map<std::string, std::set<std::string>> const & required,
33                                                      std::map<std::string, std::set<std::string>> const & optional );
34 void                                checkElements( int                                               line,
35                                                    std::vector<tinyxml2::XMLElement const *> const & elements,
36                                                    std::map<std::string, bool> const &               required,
37                                                    std::set<std::string> const &                     optional = {} );
38 void                                checkForError( bool condition, int line, std::string const & message );
39 void                                checkForWarning( bool condition, int line, std::string const & message );
40 std::string                         findTag( std::set<std::string> const & tags, std::string const & name, std::string const & postfix = "" );
41 std::string                         generateCArraySizes( std::vector<std::string> const & sizes );
42 std::pair<std::string, std::string> generateEnumSuffixes( std::string const & name, bool bitmask, std::set<std::string> const & tags );
43 std::string generateEnumValueName( std::string const & enumName, std::string const & valueName, bool bitmask, std::set<std::string> const & tags );
44 std::string generateNamespacedType( std::string const & type );
45 std::string generateNoDiscard( bool returnsSomething, bool multiSuccessCodes, bool multiErrorCodes );
46 std::string generateStandardArray( std::string const & type, std::vector<std::string> const & sizes );
47 std::string generateStandardArrayWrapper( std::string const & type, std::vector<std::string> const & sizes );
48 std::string generateSuccessCode( std::string const & code, std::set<std::string> const & tags );
49 std::map<std::string, std::string> getAttributes( tinyxml2::XMLElement const * element );
50 template <typename ElementContainer>
51 std::vector<tinyxml2::XMLElement const *>        getChildElements( ElementContainer const * element );
52 std::pair<std::vector<std::string>, std::string> readModifiers( tinyxml2::XMLNode const * node );
53 std::string                                      readSnippet( std::string const & snippetFile );
54 std::string                                      replaceWithMap( std::string const & input, std::map<std::string, std::string> replacements );
55 std::string                                      startLowerCase( std::string const & input );
56 std::string                                      startUpperCase( std::string const & input );
57 std::string                                      stripPostfix( std::string const & value, std::string const & postfix );
58 std::string                                      stripPluralS( std::string const & name, std::set<std::string> const & tags );
59 std::string                                      stripPrefix( std::string const & value, std::string const & prefix );
60 std::string                                      toCamelCase( std::string const & value );
61 std::string                                      toUpperCase( std::string const & name );
62 std::vector<std::string>                         tokenize( std::string const & tokenString, std::string const & separator );
63 std::vector<std::string>                         tokenizeAny( std::string const & tokenString, std::string const & separators );
64 std::string                                      toString( tinyxml2::XMLError error );
65 std::string                                      trim( std::string const & input );
66 std::string                                      trimEnd( std::string const & input );
67 std::string                                      trimStars( std::string const & input );
68 void                                             writeToFile( std::string const & str, std::string const & fileName );
69 
70 const std::set<std::string> altLens             = { "2*VK_UUID_SIZE", "codeSize / 4", "(rasterizationSamples + 31) / 32", "(samples + 31) / 32" };
71 const std::set<std::string> specialPointerTypes = { "Display", "IDirectFB", "wl_display", "xcb_connection_t", "_screen_window" };
72 
73 //
74 // VulkanHppGenerator public interface
75 //
76 
VulkanHppGenerator(tinyxml2::XMLDocument const & document)77 VulkanHppGenerator::VulkanHppGenerator( tinyxml2::XMLDocument const & document )
78 {
79   // insert the default "handle" without class (for createInstance, and such)
80   m_handles.insert( std::make_pair( "", HandleData( {}, "", false, 0 ) ) );
81 
82   // read the document and check its correctness
83   int                                       line     = document.GetLineNum();
84   std::vector<tinyxml2::XMLElement const *> elements = getChildElements( &document );
85   checkElements( line, elements, { { "registry", true } } );
86   checkForError( elements.size() == 1, line, "encountered " + std::to_string( elements.size() ) + " elements named <registry> but only one is allowed" );
87   readRegistry( elements[0] );
88   checkCorrectness();
89 
90   // add the commands to the respective handles
91   for ( auto & command : m_commands )
92   {
93     auto handleIt = m_handles.find( command.second.handle );
94     assert( handleIt != m_handles.end() );
95     assert( handleIt->second.commands.find( command.first ) == handleIt->second.commands.end() );
96     handleIt->second.commands.insert( command.first );
97 
98     registerDeleter( command.first, command );
99   }
100 
101   // some "FlagBits" enums are not specified, but needed for our "Flags" handling -> add them here
102   for ( auto & feature : m_features )
103   {
104     addMissingFlagBits( feature.second.requireData, feature.first );
105   }
106   for ( auto & extension : m_extensions )
107   {
108     addMissingFlagBits( extension.second.requireData, extension.first );
109   }
110 
111   // determine the extensionsByNumber map
112   for ( auto extensionIt = m_extensions.begin(); extensionIt != m_extensions.end(); ++extensionIt )
113   {
114     int number = stoi( extensionIt->second.number );
115     assert( m_extensionsByNumber.find( number ) == m_extensionsByNumber.end() );
116     m_extensionsByNumber[number] = extensionIt;
117   }
118 }
119 
generateVulkanEnumsHppFile() const120 void VulkanHppGenerator::generateVulkanEnumsHppFile() const
121 {
122   std::string const vulkan_enums_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_enums.hpp";
123   std::cout << "VulkanHppGenerator: Generating " << vulkan_enums_hpp << " ..." << std::endl;
124 
125   std::string const vulkanEnumsHppTemplate = R"(${licenseHeader}
126 #ifndef VULKAN_ENUMS_HPP
127 #  define VULKAN_ENUMS_HPP
128 
129 namespace VULKAN_HPP_NAMESPACE
130 {
131   template <typename EnumType, EnumType value>
132   struct CppType
133   {};
134 ${enums}
135 ${indexTypeTraits}
136 }   // namespace VULKAN_HPP_NAMESPACE
137 #endif
138 )";
139 
140   std::string str = replaceWithMap(
141     vulkanEnumsHppTemplate, { { "enums", generateEnums() }, { "indexTypeTraits", generateIndexTypeTraits() }, { "licenseHeader", m_vulkanLicenseHeader } } );
142 
143   writeToFile( str, vulkan_enums_hpp );
144 }
145 
generateVulkanFormatTraitsHppFile() const146 void VulkanHppGenerator::generateVulkanFormatTraitsHppFile() const
147 {
148   std::string const vulkan_format_traits_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_format_traits.hpp";
149   std::cout << "VulkanHppGenerator: Generating " << vulkan_format_traits_hpp << " ..." << std::endl;
150 
151   std::string const vulkanFormatTraitsHppTemplate = R"(${licenseHeader}
152 #ifndef VULKAN_FORMAT_TRAITS_HPP
153 #  define VULKAN_FORMAT_TRAITS_HPP
154 
155 #include <vulkan/vulkan.hpp>
156 
157 namespace VULKAN_HPP_NAMESPACE
158 {
159 ${formatTraits}
160 }   // namespace VULKAN_HPP_NAMESPACE
161 #endif
162 )";
163 
164   std::string str = replaceWithMap( vulkanFormatTraitsHppTemplate, { { "formatTraits", generateFormatTraits() }, { "licenseHeader", m_vulkanLicenseHeader } } );
165 
166   writeToFile( str, vulkan_format_traits_hpp );
167 }
168 
generateVulkanFuncsHppFile() const169 void VulkanHppGenerator::generateVulkanFuncsHppFile() const
170 {
171   std::string const vulkan_funcs_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_funcs.hpp";
172   std::cout << "VulkanHppGenerator: Generating " << vulkan_funcs_hpp << " ..." << std::endl;
173 
174   std::string const vulkanFuncsHppTemplate = R"(${licenseHeader}
175 #ifndef VULKAN_FUNCS_HPP
176 #  define VULKAN_FUNCS_HPP
177 
178 namespace VULKAN_HPP_NAMESPACE
179 {
180 ${commandDefinitions}
181 }   // namespace VULKAN_HPP_NAMESPACE
182 #endif
183 )";
184 
185   std::string str =
186     replaceWithMap( vulkanFuncsHppTemplate, { { "commandDefinitions", generateCommandDefinitions() }, { "licenseHeader", m_vulkanLicenseHeader } } );
187 
188   writeToFile( str, vulkan_funcs_hpp );
189 }
190 
generateVulkanHandlesHppFile() const191 void VulkanHppGenerator::generateVulkanHandlesHppFile() const
192 {
193   std::string const vulkan_handles_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_handles.hpp";
194   std::cout << "VulkanHppGenerator: Generating " << vulkan_handles_hpp << " ..." << std::endl;
195 
196   std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
197 #ifndef VULKAN_HANDLES_HPP
198 #  define VULKAN_HANDLES_HPP
199 
200 namespace VULKAN_HPP_NAMESPACE
201 {
202 ${structForwardDeclarations}
203 ${handles}
204 }   // namespace VULKAN_HPP_NAMESPACE
205 #endif
206 )";
207 
208   std::string str = replaceWithMap(
209     vulkanHandlesHppTemplate,
210     { { "handles", generateHandles() }, { "licenseHeader", m_vulkanLicenseHeader }, { "structForwardDeclarations", generateStructForwardDeclarations() } } );
211 
212   writeToFile( str, vulkan_handles_hpp );
213 }
214 
generateVulkanHashHppFile() const215 void VulkanHppGenerator::generateVulkanHashHppFile() const
216 {
217   std::string const vulkan_hash_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_hash.hpp";
218   std::cout << "VulkanHppGenerator: Generating " << vulkan_hash_hpp << " ..." << std::endl;
219 
220   std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
221 #ifndef VULKAN_HASH_HPP
222 #  define VULKAN_HASH_HPP
223 
224 #include <vulkan/vulkan.hpp>
225 
226 namespace std
227 {
228   //=======================================
229   //=== HASH structures for Flags types ===
230   //=======================================
231 
232   template <typename BitType>
233   struct hash<VULKAN_HPP_NAMESPACE::Flags<BitType>>
234   {
235     std::size_t operator()( VULKAN_HPP_NAMESPACE::Flags<BitType> const & flags ) const VULKAN_HPP_NOEXCEPT
236     {
237       return std::hash<typename std::underlying_type<BitType>::type>{}(
238         static_cast<typename std::underlying_type<BitType>::type>( flags ) );
239     }
240   };
241 
242 ${handleHashStructures}
243 ${structHashStructures}
244 } // namespace std
245 #endif
246 )";
247 
248   std::string str = replaceWithMap( vulkanHandlesHppTemplate,
249                                     { { "handleHashStructures", generateHandleHashStructures() },
250                                       { "licenseHeader", m_vulkanLicenseHeader },
251                                       { "structHashStructures", generateStructHashStructures() } } );
252 
253   writeToFile( str, vulkan_hash_hpp );
254 }
255 
generateVulkanHppFile() const256 void VulkanHppGenerator::generateVulkanHppFile() const
257 {
258   std::string const vulkan_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan.hpp";
259   std::cout << "VulkanHppGenerator: Generating " << vulkan_hpp << " ... " << std::endl;
260 
261   std::string const vulkanHppTemplate = R"(${licenseHeader}
262 ${includes}
263 
264 static_assert( VK_HEADER_VERSION == ${headerVersion}, "Wrong VK_HEADER_VERSION!" );
265 
266 // 32-bit vulkan is not typesafe for non-dispatchable handles, so don't allow copy constructors on this platform by default.
267 // To enable this feature on 32-bit platforms please define VULKAN_HPP_TYPESAFE_CONVERSION
268 ${typesafeCheck}
269 #  if !defined( VULKAN_HPP_TYPESAFE_CONVERSION )
270 #    define VULKAN_HPP_TYPESAFE_CONVERSION
271 #  endif
272 #endif
273 
274 ${defines}
275 
276 namespace VULKAN_HPP_NAMESPACE
277 {
278 ${ArrayWrapper1D}
279 ${ArrayWrapper2D}
280 ${Flags}
281 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
282 ${ArrayProxy}
283 ${ArrayProxyNoTemporaries}
284 ${StridedArrayProxy}
285 ${Optional}
286 ${StructureChain}
287 ${UniqueHandle}
288 #endif  // VULKAN_HPP_DISABLE_ENHANCED_MODE
289 
290 ${DispatchLoaderBase}
291 ${DispatchLoaderStatic}
292 ${DispatchLoaderDefault}
293 #if !defined( VULKAN_HPP_NO_SMART_HANDLE )
294 ${ObjectDestroy}
295 ${ObjectFree}
296 ${ObjectRelease}
297 ${PoolFree}
298 #endif // !VULKAN_HPP_NO_SMART_HANDLE
299 ${baseTypes}
300 } // namespace VULKAN_HPP_NAMESPACE
301 
302 #include <vulkan/vulkan_enums.hpp>
303 #if !defined( VULKAN_HPP_NO_TO_STRING )
304 #include <vulkan/vulkan_to_string.hpp>
305 #endif
306 
307 #ifndef VULKAN_HPP_NO_EXCEPTIONS
308 namespace std
309 {
310   template <>
311   struct is_error_code_enum<VULKAN_HPP_NAMESPACE::Result> : public true_type
312   {};
313 }  // namespace std
314 #endif
315 
316 namespace VULKAN_HPP_NAMESPACE
317 {
318 #ifndef VULKAN_HPP_NO_EXCEPTIONS
319 ${Exceptions}
320 ${resultExceptions}
321 ${throwResultException}
322 #endif
323 
324 ${ResultValue}
325 ${resultChecks}
326 } // namespace VULKAN_HPP_NAMESPACE
327 
328 // clang-format off
329 #include <vulkan/vulkan_handles.hpp>
330 #include <vulkan/vulkan_structs.hpp>
331 #include <vulkan/vulkan_funcs.hpp>
332 // clang-format on
333 
334 namespace VULKAN_HPP_NAMESPACE
335 {
336 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
337 ${structExtendsStructs}
338 #endif // VULKAN_HPP_DISABLE_ENHANCED_MODE
339 
340 ${DynamicLoader}
341 ${DispatchLoaderDynamic}
342 }   // namespace VULKAN_HPP_NAMESPACE
343 #endif
344 )";
345 
346   std::string str = replaceWithMap( vulkanHppTemplate,
347                                     { { "ArrayProxy", readSnippet( "ArrayProxy.hpp" ) },
348                                       { "ArrayProxyNoTemporaries", readSnippet( "ArrayProxyNoTemporaries.hpp" ) },
349                                       { "ArrayWrapper1D", readSnippet( "ArrayWrapper1D.hpp" ) },
350                                       { "ArrayWrapper2D", readSnippet( "ArrayWrapper2D.hpp" ) },
351                                       { "baseTypes", generateBaseTypes() },
352                                       { "defines", readSnippet( "defines.hpp" ) },
353                                       { "DispatchLoaderBase", readSnippet( "DispatchLoaderBase.hpp" ) },
354                                       { "DispatchLoaderDefault", readSnippet( "DispatchLoaderDefault.hpp" ) },
355                                       { "DispatchLoaderDynamic", generateDispatchLoaderDynamic() },
356                                       { "DispatchLoaderStatic", generateDispatchLoaderStatic() },
357                                       { "DynamicLoader", readSnippet( "DynamicLoader.hpp" ) },
358                                       { "Exceptions", readSnippet( "Exceptions.hpp" ) },
359                                       { "Flags", readSnippet( "Flags.hpp" ) },
360                                       { "headerVersion", m_version },
361                                       { "includes", readSnippet( "includes.hpp" ) },
362                                       { "licenseHeader", m_vulkanLicenseHeader },
363                                       { "ObjectDestroy", readSnippet( "ObjectDestroy.hpp" ) },
364                                       { "ObjectFree", readSnippet( "ObjectFree.hpp" ) },
365                                       { "ObjectRelease", readSnippet( "ObjectRelease.hpp" ) },
366                                       { "Optional", readSnippet( "Optional.hpp" ) },
367                                       { "PoolFree", readSnippet( "PoolFree.hpp" ) },
368                                       { "resultChecks", readSnippet( "resultChecks.hpp" ) },
369                                       { "resultExceptions", generateResultExceptions() },
370                                       { "structExtendsStructs", generateStructExtendsStructs() },
371                                       { "ResultValue", readSnippet( "ResultValue.hpp" ) },
372                                       { "StridedArrayProxy", readSnippet( "StridedArrayProxy.hpp" ) },
373                                       { "StructureChain", readSnippet( "StructureChain.hpp" ) },
374                                       { "throwResultException", generateThrowResultException() },
375                                       { "typesafeCheck", m_typesafeCheck },
376                                       { "UniqueHandle", readSnippet( "UniqueHandle.hpp" ) } } );
377 
378   writeToFile( str, vulkan_hpp );
379 }
380 
generateVulkanRAIIHppFile() const381 void VulkanHppGenerator::generateVulkanRAIIHppFile() const
382 {
383   std::string const vulkan_raii_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_raii.hpp";
384   std::cout << "VulkanHppGenerator: Generating " << vulkan_raii_hpp << " ..." << std::endl;
385 
386   std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
387 #ifndef VULKAN_RAII_HPP
388 #define VULKAN_RAII_HPP
389 
390 #include <memory>
391 #include <utility>  // std::exchange, std::forward
392 #include <vulkan/vulkan.hpp>
393 
394 #include <android-base/expected.h>
395 #include <android-base/logging.h>
396 
397 #if !defined( VULKAN_HPP_RAII_NAMESPACE )
398 #  define VULKAN_HPP_RAII_NAMESPACE raii
399 #endif
400 
401 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
402 namespace VULKAN_HPP_NAMESPACE
403 {
404   namespace VULKAN_HPP_RAII_NAMESPACE
405   {
406     template <class T, class U = T>
407     VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_INLINE T exchange( T & obj, U && newValue )
408     {
409 #  if ( 14 <= VULKAN_HPP_CPP_VERSION )
410       return std::exchange<T>( obj, std::forward<U>( newValue ) );
411 #  else
412       T oldValue = std::move( obj );
413       obj        = std::forward<U>( newValue );
414       return oldValue;
415 #  endif
416     }
417 
418 ${RAIIDispatchers}
419 ${RAIIHandles}
420 ${RAIICommandDefinitions}
421   } // namespace VULKAN_HPP_RAII_NAMESPACE
422 }   // namespace VULKAN_HPP_NAMESPACE
423 #endif
424 #endif
425 )";
426 
427   std::string str = replaceWithMap( vulkanHandlesHppTemplate,
428                                     { { "licenseHeader", m_vulkanLicenseHeader },
429                                       { "RAIICommandDefinitions", generateRAIICommandDefinitions() },
430                                       { "RAIIDispatchers", generateRAIIDispatchers() },
431                                       { "RAIIHandles", generateRAIIHandles() } } );
432 
433   writeToFile( str, vulkan_raii_hpp );
434 }
435 
generateVulkanStaticAssertionsHppFile() const436 void VulkanHppGenerator::generateVulkanStaticAssertionsHppFile() const
437 {
438   std::string const static_assertions_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_static_assertions.hpp";
439   std::cout << "VulkanHppGenerator: Generating " << static_assertions_hpp << " ..." << std::endl;
440 
441   std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
442 #ifndef VULKAN_STATIC_ASSERTIONS_HPP
443 #  define VULKAN_STATIC_ASSERTIONS_HPP
444 
445 #include <vulkan/vulkan.hpp>
446 
447 //=========================
448 //=== static_assertions ===
449 //=========================
450 
451 ${staticAssertions}
452 #endif
453 )";
454 
455   std::string str =
456     replaceWithMap( vulkanHandlesHppTemplate, { { "licenseHeader", m_vulkanLicenseHeader }, { "staticAssertions", generateStaticAssertions() } } );
457 
458   writeToFile( str, static_assertions_hpp );
459 }
460 
generateVulkanStructsHppFile() const461 void VulkanHppGenerator::generateVulkanStructsHppFile() const
462 {
463   std::string const vulkan_structs_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_structs.hpp";
464   std::cout << "VulkanHppGenerator: Generating " << vulkan_structs_hpp << " ..." << std::endl;
465 
466   std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
467 #ifndef VULKAN_STRUCTS_HPP
468 #  define VULKAN_STRUCTS_HPP
469 
470 #include <cstring>  // strcmp
471 
472 namespace VULKAN_HPP_NAMESPACE
473 {
474 ${structs}
475 }   // namespace VULKAN_HPP_NAMESPACE
476 #endif
477 )";
478 
479   std::string str = replaceWithMap( vulkanHandlesHppTemplate, { { "licenseHeader", m_vulkanLicenseHeader }, { "structs", generateStructs() } } );
480 
481   writeToFile( str, vulkan_structs_hpp );
482 }
483 
generateVulkanToStringHppFile() const484 void VulkanHppGenerator::generateVulkanToStringHppFile() const
485 {
486   std::string const vulkan_to_string_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_to_string.hpp";
487   std::cout << "VulkanHppGenerator: Generating " << vulkan_to_string_hpp << "..." << std::endl;
488 
489   std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
490 #ifndef VULKAN_TO_STRING_HPP
491 #  define VULKAN_TO_STRING_HPP
492 
493 #include <vulkan/vulkan_enums.hpp>
494 
495 #if __cpp_lib_format
496 #  include <format>   // std::format
497 #else
498 #  include <sstream>  // std::stringstream
499 #endif
500 
501 namespace VULKAN_HPP_NAMESPACE
502 {
503 ${bitmasksToString}
504 ${enumsToString}
505 } // namespace VULKAN_HPP_NAMESPACE
506 #endif
507 )";
508 
509   std::string str = replaceWithMap(
510     vulkanHandlesHppTemplate,
511     { { "bitmasksToString", generateBitmasksToString() }, { "enumsToString", generateEnumsToString() }, { "licenseHeader", m_vulkanLicenseHeader } } );
512 
513   writeToFile( str, vulkan_to_string_hpp );
514 }
515 
prepareRAIIHandles()516 void VulkanHppGenerator::prepareRAIIHandles()
517 {
518   // filter out functions that are not usefull on this level of abstraction (like vkGetInstanceProcAddr)
519   // and all the construction and destruction functions, as they are used differently
520   assert( m_handles.begin()->first.empty() );
521   for ( auto handleIt = std::next( m_handles.begin() ); handleIt != m_handles.end(); ++handleIt )
522   {
523     handleIt->second.destructorIt = determineRAIIHandleDestructor( handleIt->first );
524     if ( handleIt->second.destructorIt != m_commands.end() )
525     {
526       m_RAIISpecialFunctions.insert( handleIt->second.destructorIt->first );
527     }
528     handleIt->second.constructorIts = determineRAIIHandleConstructors( handleIt->first, handleIt->second.destructorIt );
529   }
530 
531   distributeSecondLevelCommands( m_RAIISpecialFunctions );
532 }
533 
prepareVulkanFuncs()534 void VulkanHppGenerator::prepareVulkanFuncs()
535 {
536   // rename a couple of function parameters to prevent this warning, treated as an error:
537   // warning C4458: declaration of 'objectType' hides class member
538   for ( auto & command : m_commands )
539   {
540     for ( auto & param : command.second.params )
541     {
542       if ( param.name == "objectType" )
543       {
544         param.name += "_";
545       }
546     }
547   }
548 }
549 
550 //
551 // VulkanHppGenerator private interface
552 //
553 
addCommand(std::string const & name,CommandData & commandData)554 void VulkanHppGenerator::addCommand( std::string const & name, CommandData & commandData )
555 {
556   // find the handle this command is going to be associated to
557   checkForError( !commandData.params.empty(), commandData.xmlLine, "command <" + name + "> with no params" );
558   std::map<std::string, HandleData>::iterator handleIt = m_handles.find( commandData.params[0].type.type );
559   if ( handleIt == m_handles.end() )
560   {
561     handleIt = m_handles.begin();
562     assert( handleIt->first == "" );
563   }
564   commandData.handle = handleIt->first;
565 
566   // add this command to the list of commands
567   checkForError( m_commands.insert( std::make_pair( name, commandData ) ).second, commandData.xmlLine, "already encountered command <" + name + ">" );
568 }
569 
addMissingFlagBits(std::vector<RequireData> & requireData,std::string const & referencedIn)570 void VulkanHppGenerator::addMissingFlagBits( std::vector<RequireData> & requireData, std::string const & referencedIn )
571 {
572   for ( auto & require : requireData )
573   {
574     std::vector<std::string> newTypes;
575     for ( auto const & type : require.types )
576     {
577       auto bitmaskIt = m_bitmasks.find( type );
578       if ( ( bitmaskIt != m_bitmasks.end() ) && bitmaskIt->second.requirements.empty() )
579       {
580         // generate the flagBits enum name out of the bitmask name: VkFooFlagsXXX -> VkFooFlagBitsXXX
581         size_t pos = bitmaskIt->first.find( "Flags" );
582         assert( pos != std::string::npos );
583         std::string flagBits = bitmaskIt->first.substr( 0, pos + 4 ) + "Bit" + bitmaskIt->first.substr( pos + 4 );
584 
585         // as the bitmask's requirement is still empty, this flagBits should not be listed in the require list!
586         assert( std::find_if( require.types.begin(), require.types.end(), [&flagBits]( std::string const & type ) { return ( type == flagBits ); } ) ==
587                 require.types.end() );
588 
589         bitmaskIt->second.requirements = flagBits;
590 
591         // some flagsBits are specified but never listed as required for any flags!
592         // so, even if this bitmask has no enum listed as required, it might still already exist in the enums list
593         auto enumIt = m_enums.find( flagBits );
594         if ( enumIt == m_enums.end() )
595         {
596           m_enums.insert( std::make_pair( flagBits, EnumData{ .isBitmask = true, .xmlLine = 0 } ) );
597 
598           assert( m_types.find( flagBits ) == m_types.end() );
599           m_types.insert( std::make_pair( flagBits, TypeData{ .category = TypeCategory::Bitmask, .referencedIn = referencedIn } ) );
600         }
601         else
602         {
603           assert( m_types.find( flagBits ) != m_types.end() );
604           enumIt->second.isBitmask = true;
605         }
606 
607         newTypes.push_back( flagBits );
608       }
609     }
610     // add all the newly created flagBits types to the require list as if they had been part of the vk.xml!
611     require.types.insert( require.types.end(), newTypes.begin(), newTypes.end() );
612   }
613 }
614 
addTitleAndProtection(std::string const & title,std::string const & strIf,std::string const & strElse) const615 std::string VulkanHppGenerator::addTitleAndProtection( std::string const & title, std::string const & strIf, std::string const & strElse ) const
616 {
617   std::string str;
618   if ( !strIf.empty() )
619   {
620     auto [enter, leave] = generateProtection( getProtectFromTitle( title ) );
621     str                 = "\n" + enter + "  //=== " + title + " ===\n" + strIf;
622     if ( !enter.empty() && !strElse.empty() )
623     {
624       str += "#else \n" + strElse;
625     }
626     str += leave;
627   }
628   return str;
629 }
630 
allVectorSizesSupported(std::vector<ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams) const631 bool VulkanHppGenerator::allVectorSizesSupported( std::vector<ParamData> const & params, std::map<size_t, VectorParamData> const & vectorParams ) const
632 {
633   // check if all vector sizes are by value and their type is one of "uint32_t", "VkDeviceSize", or "VkSampleCountFlagBits"
634   return std::find_if_not( vectorParams.begin(),
635                            vectorParams.end(),
636                            [&params]( auto const & vpi )
637                            {
638                              return params[vpi.second.lenParam].type.isValue() &&
639                                     ( ( params[vpi.second.lenParam].type.type == "uint32_t" ) || ( params[vpi.second.lenParam].type.type == "VkDeviceSize" ) ||
640                                       ( params[vpi.second.lenParam].type.type == "VkSampleCountFlagBits" ) );
641                            } ) == vectorParams.end();
642 }
643 
appendDispatchLoaderDynamicCommands(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title,std::string & commandMembers,std::string & initialCommandAssignments,std::string & instanceCommandAssignments,std::string & deviceCommandAssignments) const644 void VulkanHppGenerator::appendDispatchLoaderDynamicCommands( std::vector<RequireData> const & requireData,
645                                                               std::set<std::string> &          listedCommands,
646                                                               std::string const &              title,
647                                                               std::string &                    commandMembers,
648                                                               std::string &                    initialCommandAssignments,
649                                                               std::string &                    instanceCommandAssignments,
650                                                               std::string &                    deviceCommandAssignments ) const
651 {
652   std::string members, initial, instance, device, placeholders;
653   for ( auto const & require : requireData )
654   {
655     for ( auto const & command : require.commands )
656     {
657       if ( listedCommands.insert( command ).second )
658       {
659         auto commandIt = m_commands.find( command );
660         assert( commandIt != m_commands.end() );
661 
662         members += "    PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
663         placeholders += "    PFN_dummy " + commandIt->first + "_placeholder = 0;\n";
664         if ( commandIt->second.handle.empty() )
665         {
666           initial += generateDispatchLoaderDynamicCommandAssignment( commandIt->first, commandIt->second, "NULL" );
667         }
668         else
669         {
670           instance += generateDispatchLoaderDynamicCommandAssignment( commandIt->first, commandIt->second, "instance" );
671           if ( isDeviceCommand( commandIt->second ) )
672           {
673             device += generateDispatchLoaderDynamicCommandAssignment( commandIt->first, commandIt->second, "device" );
674           }
675         }
676       }
677     }
678   }
679   auto [enter, leave] = generateProtection( getProtectFromTitle( title ) );
680   std::string header  = "\n" + enter + "  //=== " + title + " ===\n";
681   if ( !members.empty() )
682   {
683     commandMembers += header + members;
684     if ( !enter.empty() )
685     {
686       commandMembers += "#else\n" + placeholders;
687     }
688     commandMembers += leave;
689   }
690   if ( !initial.empty() )
691   {
692     initialCommandAssignments += header + initial + leave;
693   }
694   if ( !instance.empty() )
695   {
696     instanceCommandAssignments += header + instance + leave;
697   }
698   if ( !device.empty() )
699   {
700     deviceCommandAssignments += header + device + leave;
701   }
702 }
703 
appendRAIIDispatcherCommands(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title,std::string & contextInitializers,std::string & contextMembers,std::string & deviceAssignments,std::string & deviceMembers,std::string & instanceAssignments,std::string & instanceMembers) const704 void VulkanHppGenerator::appendRAIIDispatcherCommands( std::vector<RequireData> const & requireData,
705                                                        std::set<std::string> &          listedCommands,
706                                                        std::string const &              title,
707                                                        std::string &                    contextInitializers,
708                                                        std::string &                    contextMembers,
709                                                        std::string &                    deviceAssignments,
710                                                        std::string &                    deviceMembers,
711                                                        std::string &                    instanceAssignments,
712                                                        std::string &                    instanceMembers ) const
713 {
714   std::string ci, cm, da, dm, dmp, ia, im, imp;
715   for ( auto const & require : requireData )
716   {
717     for ( auto const & command : require.commands )
718     {
719       if ( listedCommands.insert( command ).second )
720       {
721         auto commandIt = m_commands.find( command );
722         assert( commandIt != m_commands.end() );
723         if ( commandIt->second.handle.empty() )
724         {
725           assert( commandIt->second.alias.empty() );
726 
727           ci += ", " + commandIt->first + "( PFN_" + commandIt->first + "( getProcAddr( NULL, \"" + commandIt->first + "\" ) ) )";
728 
729           cm += "      PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
730         }
731         else if ( ( commandIt->second.handle == "VkDevice" ) || hasParentHandle( commandIt->second.handle, "VkDevice" ) )
732         {
733           da += "        " + commandIt->first + " = PFN_" + commandIt->first + "( vkGetDeviceProcAddr( device, \"" + commandIt->first + "\" ) );\n";
734           // if this is an alias'ed function, use it as a fallback for the original one
735           if ( !commandIt->second.alias.empty() )
736           {
737             da += "        if ( !" + commandIt->second.alias + " ) " + commandIt->second.alias + " = " + commandIt->first + ";\n";
738           }
739 
740           dm += "      PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
741           dmp += "      PFN_dummy " + commandIt->first + "_placeholder = 0;\n";
742         }
743         else
744         {
745           assert( ( commandIt->second.handle == "VkInstance" ) || hasParentHandle( commandIt->second.handle, "VkInstance" ) );
746 
747           // filter out vkGetInstanceProcAddr, as starting with Vulkan 1.2 it can resolve itself only (!) with an
748           // instance nullptr !
749           if ( command != "vkGetInstanceProcAddr" )
750           {
751             ia += "        " + commandIt->first + " = PFN_" + commandIt->first + "( vkGetInstanceProcAddr( instance, \"" + commandIt->first + "\" ) );\n";
752             // if this is an alias'ed function, use it as a fallback for the original one
753             if ( !commandIt->second.alias.empty() )
754             {
755               ia += "        if ( !" + commandIt->second.alias + " ) " + commandIt->second.alias + " = " + commandIt->first + ";\n";
756             }
757           }
758 
759           im += +"      PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
760           imp += "      PFN_dummy " + commandIt->first + "_placeholder = 0;\n";
761         }
762       }
763     }
764   }
765   contextInitializers += addTitleAndProtection( title, ci );
766   contextMembers += addTitleAndProtection( title, cm );
767   deviceAssignments += addTitleAndProtection( title, da );
768   deviceMembers += addTitleAndProtection( title, dm, dmp );
769   instanceAssignments += addTitleAndProtection( title, ia );
770   instanceMembers += addTitleAndProtection( title, im, imp );
771 }
772 
checkBitmaskCorrectness() const773 void VulkanHppGenerator::checkBitmaskCorrectness() const
774 {
775   for ( auto const & bitmask : m_bitmasks )
776   {
777     // check that a bitmask is referenced somewhere
778     // I think, it's not forbidden to not reference a bitmask, but it would probably be not intended?
779     auto typeIt = m_types.find( bitmask.first );
780     assert( typeIt != m_types.end() );
781     checkForError( !typeIt->second.referencedIn.empty(), bitmask.second.xmlLine, "bitmask <" + bitmask.first + "> not listed in any feature or extension" );
782 
783     // check that the requirement is an enum
784     if ( !bitmask.second.requirements.empty() )
785     {
786       checkForError( m_enums.find( bitmask.second.requirements ) != m_enums.end(),
787                      bitmask.second.xmlLine,
788                      "bitmask requires unknown <" + bitmask.second.requirements + ">" );
789     }
790   }
791 }
792 
checkCommandCorrectness() const793 void VulkanHppGenerator::checkCommandCorrectness() const
794 {
795   // prepare command checks by gathering all result codes and aliases into one set of resultCodes
796   auto resultIt = m_enums.find( "VkResult" );
797   assert( resultIt != m_enums.end() );
798   std::set<std::string> resultCodes;
799   for ( auto rc : resultIt->second.values )
800   {
801     resultCodes.insert( rc.name );
802   }
803   for ( auto rc : resultIt->second.aliases )
804   {
805     resultCodes.insert( rc.first );
806   }
807 
808   // command checks
809   for ( auto const & command : m_commands )
810   {
811     // check that a command is referenced somewhere
812     // I think, it's not forbidden to not reference a function, but it would probably be not intended?
813     checkForError( !command.second.referencedIn.empty(), command.second.xmlLine, "command <" + command.first + "> not listed in any feature or extension" );
814 
815     // check for unknown error or succes codes
816     for ( auto const & ec : command.second.errorCodes )
817     {
818       checkForError( resultCodes.find( ec ) != resultCodes.end(), command.second.xmlLine, "command uses unknown error code <" + ec + ">" );
819     }
820     for ( auto const & sc : command.second.successCodes )
821     {
822       checkForError( resultCodes.find( sc ) != resultCodes.end(), command.second.xmlLine, "command uses unknown success code <" + sc + ">" );
823     }
824 
825     // check that functions returning a VkResult specify successcodes
826     checkForError( ( command.second.returnType != "VkResult" ) || !command.second.successCodes.empty(),
827                    command.second.xmlLine,
828                    "missing successcodes on command <" + command.first + "> returning VkResult!" );
829 
830     // check that all parameter types as well as the return type are known types
831     for ( auto const & p : command.second.params )
832     {
833       checkForError( m_types.find( p.type.type ) != m_types.end(), p.xmlLine, "comand uses parameter of unknown type <" + p.type.type + ">" );
834     }
835     checkForError( m_types.find( command.second.returnType ) != m_types.end(),
836                    command.second.xmlLine,
837                    "command uses unknown return type <" + command.second.returnType + ">" );
838   }
839 }
840 
checkCorrectness() const841 void VulkanHppGenerator::checkCorrectness() const
842 {
843   checkForError( !m_vulkanLicenseHeader.empty(), -1, "missing license header" );
844   checkBitmaskCorrectness();
845   checkCommandCorrectness();
846   checkDefineCorrectness();
847   checkEnumCorrectness();
848   checkExtensionCorrectness();
849   checkFuncPointerCorrectness();
850   checkHandleCorrectness();
851   checkStructCorrectness();
852 }
853 
checkDefineCorrectness() const854 void VulkanHppGenerator::checkDefineCorrectness() const
855 {
856   for ( auto const & d : m_defines )
857   {
858     checkForError( d.second.require.empty() || ( m_defines.find( d.second.require ) != m_defines.end() ),
859                    d.second.xmlLine,
860                    "using undefined require <" + d.second.require + ">" );
861   }
862 }
863 
checkEnumCorrectness() const864 void VulkanHppGenerator::checkEnumCorrectness() const
865 {
866   for ( auto const & e : m_enums )
867   {
868     // check that a bitmask is referenced somewhere
869     // it's not forbidden to not reference a bitmask, and in fact that happens! So just warn here
870     auto typeIt = m_types.find( e.first );
871     assert( typeIt != m_types.end() );
872     checkForWarning( !typeIt->second.referencedIn.empty(), e.second.xmlLine, "enum <" + e.first + "> not listed in any feature or extension" );
873 
874     // check that the aliasNames are known enum values or known aliases
875     for ( auto const & alias : e.second.aliases )
876     {
877       checkForError(
878         ( std::find_if( e.second.values.begin(), e.second.values.end(), [&alias]( EnumValueData const & evd ) { return evd.name == alias.second.name; } ) !=
879           e.second.values.end() ) ||
880           ( e.second.aliases.find( alias.second.name ) != e.second.aliases.end() ),
881         alias.second.xmlLine,
882         "enum <" + alias.first + "> uses unknown alias <" + alias.second.name + ">" );
883     }
884 
885     // check that any protection fits to the corresponding extension
886     for ( auto const & v : e.second.values )
887     {
888       if ( !v.protect.empty() )
889       {
890         auto extIt = m_extensions.find( v.extension );
891         assert( extIt != m_extensions.end() );
892         auto platformIt = m_platforms.find( extIt->second.platform );
893         assert( platformIt != m_platforms.end() );
894         checkForError( v.protect == platformIt->second.protect,
895                        v.xmlLine,
896                        "attribute <protect> of enum value <" + v.name + "> is \"" + v.protect + "\" but corresponding extension <" + v.extension +
897                          "> belongs to platform <" + platformIt->first + "> with protection \"" + platformIt->second.protect + "\"" );
898       }
899     }
900   }
901 
902   // enum checks by features and extensions
903   for ( auto & feature : m_features )
904   {
905     checkEnumCorrectness( feature.second.requireData );
906   }
907   for ( auto & ext : m_extensions )
908   {
909     checkEnumCorrectness( ext.second.requireData );
910   }
911 
912   // special check for VkFormat
913   if ( !m_formats.empty() )
914   {
915     auto enumIt = m_enums.find( "VkFormat" );
916     assert( enumIt != m_enums.end() );
917     assert( enumIt->second.values.front().name == "VK_FORMAT_UNDEFINED" );
918     for ( auto enumValueIt = std::next( enumIt->second.values.begin() ); enumValueIt != enumIt->second.values.end(); ++enumValueIt )
919     {
920       auto formatIt = m_formats.find( enumValueIt->name );
921       if ( formatIt == m_formats.end() )
922       {
923         auto aliasIt = std::find_if(
924           enumIt->second.aliases.begin(), enumIt->second.aliases.end(), [&enumValueIt]( auto const & ead ) { return ead.second.name == enumValueIt->name; } );
925         checkForError( aliasIt != enumIt->second.aliases.end(), enumValueIt->xmlLine, "missing format specification for <" + enumValueIt->name + ">" );
926       }
927     }
928   }
929 }
930 
checkEnumCorrectness(std::vector<RequireData> const & requireData) const931 void VulkanHppGenerator::checkEnumCorrectness( std::vector<RequireData> const & requireData ) const
932 {
933   for ( auto const & require : requireData )
934   {
935     for ( auto const & type : require.types )
936     {
937       auto typeIt = m_types.find( type );
938       assert( typeIt != m_types.end() );
939       switch ( typeIt->second.category )
940       {
941         case TypeCategory::Bitmask:
942           {
943             // check that each "require" listed for a bitmask is listed for a feature or an extension
944             auto bitmaskIt = m_bitmasks.find( type );
945             if ( bitmaskIt != m_bitmasks.end() )
946             {
947               // not for every bitmask is a "require" listed
948               if ( !bitmaskIt->second.requirements.empty() )
949               {
950                 auto requireTypeIt = m_types.find( bitmaskIt->second.requirements );
951                 assert( requireTypeIt != m_types.end() );
952                 checkForError( !requireTypeIt->second.referencedIn.empty(),
953                                bitmaskIt->second.xmlLine,
954                                "bitmask <" + bitmaskIt->first + "> requires <" + bitmaskIt->second.requirements +
955                                  "> which is not listed for any feature or extension!" );
956               }
957             }
958             else
959             {
960               // every bitmask not listed in the m_bitmasks, should be an alias of such a thing
961               assert( std::find_if( m_bitmasks.begin(),
962                                     m_bitmasks.end(),
963                                     [&type]( std::pair<const std::string, BitmaskData> const & bd ) { return bd.second.alias == type; } ) != m_bitmasks.end() );
964             }
965           }
966           break;
967         case TypeCategory::Enum:
968           {
969             auto enumIt = m_enums.find( type );
970             if ( enumIt != m_enums.end() )
971             {
972               if ( enumIt->second.isBitmask )
973               {
974                 // check that any enum of a bitmask is listed as "require" or "bitvalues" for a bitmask
975                 auto bitmaskIt = std::find_if(
976                   m_bitmasks.begin(), m_bitmasks.end(), [&enumIt]( auto const & bitmask ) { return bitmask.second.requirements == enumIt->first; } );
977                 checkForError( bitmaskIt != m_bitmasks.end(),
978                                enumIt->second.xmlLine,
979                                "enum <" + enumIt->first + "> is not listed as an requires or bitvalues for any bitmask in the types section" );
980 
981                 // check that bitwidth of the enum and type of the corresponding bitmask are equal
982                 checkForError( ( enumIt->second.bitwidth != "64" ) || ( bitmaskIt->second.type == "VkFlags64" ),
983                                enumIt->second.xmlLine,
984                                "enum <" + enumIt->first + "> is marked with bitwidth <64> but corresponding bitmask <" + bitmaskIt->first +
985                                  "> is not of type <VkFlags64>" );
986               }
987             }
988             else
989             {
990               // every enum not listed in the m_enums, should be an alias of such a thing
991               assert( std::find_if( m_enums.begin(),
992                                     m_enums.end(),
993                                     [&type]( std::pair<const std::string, EnumData> const & ed ) { return ed.second.alias == type; } ) != m_enums.end() );
994             }
995           }
996           break;
997         default: break;
998       }
999     }
1000   }
1001 }
1002 
checkEquivalentSingularConstructor(std::vector<std::map<std::string,CommandData>::const_iterator> const & constructorIts,std::map<std::string,CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator lenIt) const1003 bool VulkanHppGenerator::checkEquivalentSingularConstructor( std::vector<std::map<std::string, CommandData>::const_iterator> const & constructorIts,
1004                                                              std::map<std::string, CommandData>::const_iterator                      constructorIt,
1005                                                              std::vector<ParamData>::const_iterator                                  lenIt ) const
1006 {
1007   // check, if there is no singular constructor with the very same arguments as this array constructor
1008   // (besides the size, of course)
1009   auto isEquivalentSingularConstructor = [constructorIt, lenIt]( std::map<std::string, CommandData>::const_iterator it )
1010   {
1011     if ( it->second.params.size() + 1 != constructorIt->second.params.size() )
1012     {
1013       return false;
1014     }
1015     size_t lenIdx = std::distance( constructorIt->second.params.begin(), lenIt );
1016     for ( size_t i = 0, j = 0; i < it->second.params.size(); ++i, ++j )
1017     {
1018       assert( j < constructorIt->second.params.size() );
1019       if ( j == lenIdx )
1020       {
1021         ++j;
1022       }
1023       if ( it->second.params[i].type.type != constructorIt->second.params[j].type.type )
1024       {
1025         return false;
1026       }
1027     }
1028     return true;
1029   };
1030   return ( std::find_if( constructorIts.begin(), constructorIts.end(), isEquivalentSingularConstructor ) != constructorIts.end() );
1031 }
1032 
checkExtensionCorrectness() const1033 void VulkanHppGenerator::checkExtensionCorrectness() const
1034 {
1035   for ( auto const & extension : m_extensions )
1036   {
1037     // check for existence of any deprecation, obsoletion, or promotion
1038     if ( !extension.second.deprecatedBy.empty() )
1039     {
1040       checkForError( ( m_extensions.find( extension.second.deprecatedBy ) != m_extensions.end() ) ||
1041                        ( m_features.find( extension.second.deprecatedBy ) != m_features.end() ),
1042                      extension.second.xmlLine,
1043                      "extension deprecated by unknown extension/version <" + extension.second.promotedTo + ">" );
1044     }
1045     if ( !extension.second.obsoletedBy.empty() )
1046     {
1047       checkForError( ( m_extensions.find( extension.second.obsoletedBy ) != m_extensions.end() ) ||
1048                        ( m_features.find( extension.second.obsoletedBy ) != m_features.end() ),
1049                      extension.second.xmlLine,
1050                      "extension obsoleted by unknown extension/version <" + extension.second.promotedTo + ">" );
1051     }
1052     if ( !extension.second.promotedTo.empty() )
1053     {
1054       checkForError( ( m_extensions.find( extension.second.promotedTo ) != m_extensions.end() ) ||
1055                        ( m_features.find( extension.second.promotedTo ) != m_features.end() ),
1056                      extension.second.xmlLine,
1057                      "extension promoted to unknown extension/version <" + extension.second.promotedTo + ">" );
1058     }
1059 
1060     // check for existence of any requirement
1061     for ( auto const & require : extension.second.requireData )
1062     {
1063       if ( !require.depends.empty() )
1064       {
1065         for ( auto const & depends : require.depends )
1066         {
1067           checkForError( ( m_features.find( depends ) != m_features.end() ) || ( m_extensions.find( depends ) != m_extensions.end() ),
1068                          require.xmlLine,
1069                          "extension <" + extension.first + "> lists an unknown depends <" + depends + ">" );
1070         }
1071       }
1072     }
1073   }
1074 }
1075 
checkFuncPointerCorrectness() const1076 void VulkanHppGenerator::checkFuncPointerCorrectness() const
1077 {
1078   for ( auto const & funcPointer : m_funcPointers )
1079   {
1080     if ( !funcPointer.second.requirements.empty() )
1081     {
1082       checkForError( m_types.find( funcPointer.second.requirements ) != m_types.end(),
1083                      funcPointer.second.xmlLine,
1084                      "funcpointer requires unknown <" + funcPointer.second.requirements + ">" );
1085     }
1086     for ( auto const & argument : funcPointer.second.arguments )
1087     {
1088       checkForError( m_types.find( argument.type ) != m_types.end(), argument.xmlLine, "funcpointer argument of unknown type <" + argument.type + ">" );
1089     }
1090   }
1091 }
1092 
checkHandleCorrectness() const1093 void VulkanHppGenerator::checkHandleCorrectness() const
1094 {
1095   // prepare handle checks by getting the VkObjectType enum
1096   auto objectTypeIt = m_enums.find( "VkObjectType" );
1097   assert( objectTypeIt != m_enums.end() );
1098 
1099   // handle checks
1100   for ( auto const & handle : m_handles )
1101   {
1102     // check the existence of the parent
1103     checkForError( m_handles.find( handle.second.parent ) != m_handles.end(),
1104                    handle.second.xmlLine,
1105                    "handle <" + handle.first + "> with unknown parent <" + handle.second.parent + ">" );
1106 
1107     // check existence of objTypeEnum used with this handle type
1108     if ( !handle.first.empty() )
1109     {
1110       assert( !handle.second.objTypeEnum.empty() );
1111       checkForError( std::find_if( objectTypeIt->second.values.begin(),
1112                                    objectTypeIt->second.values.end(),
1113                                    [&handle]( EnumValueData const & evd )
1114                                    { return evd.name == handle.second.objTypeEnum; } ) != objectTypeIt->second.values.end(),
1115                      handle.second.xmlLine,
1116                      "handle <" + handle.first + "> specifies unknown \"objtypeenum\" <" + handle.second.objTypeEnum + ">" );
1117     }
1118   }
1119 
1120   // check that all specified objectType values are used with a handle type
1121   for ( auto const & objectTypeValue : objectTypeIt->second.values )
1122   {
1123     if ( objectTypeValue.name != "VK_OBJECT_TYPE_UNKNOWN" )
1124     {
1125       checkForError( std::find_if( m_handles.begin(),
1126                                    m_handles.end(),
1127                                    [&objectTypeValue]( std::pair<std::string, HandleData> const & hd )
1128                                    { return hd.second.objTypeEnum == objectTypeValue.name; } ) != m_handles.end(),
1129                      objectTypeValue.xmlLine,
1130                      "VkObjectType value <" + objectTypeValue.name + "> not specified as \"objtypeenum\" for any handle" );
1131     }
1132   }
1133 }
1134 
checkStructCorrectness() const1135 void VulkanHppGenerator::checkStructCorrectness() const
1136 {
1137   for ( auto const & structAlias : m_structureAliases )
1138   {
1139     auto structIt = m_structures.find( structAlias.second.alias );
1140     checkForError( structIt != m_structures.end(), structAlias.second.xmlLine, "unknown struct alias <" + structAlias.second.alias + ">" );
1141   }
1142 
1143   for ( auto const & structAliasInverse : m_structureAliasesInverse )
1144   {
1145     auto structIt = m_structures.find( structAliasInverse.first );
1146     if ( structIt == m_structures.end() )
1147     {
1148       assert( !structAliasInverse.second.empty() );
1149       auto aliasIt = m_structureAliases.find( *structAliasInverse.second.begin() );
1150       assert( aliasIt != m_structureAliases.end() );
1151       checkForError( false, aliasIt->second.xmlLine, "struct <" + aliasIt->first + "> uses unknown alias <" + aliasIt->second.alias + ">" );
1152     }
1153   }
1154 
1155   std::set<std::string> sTypeValues;
1156   for ( auto const & structure : m_structures )
1157   {
1158     // check that a struct is referenced somewhere
1159     // I think, it's not forbidden to not reference a struct, but it would probably be not intended?
1160     auto typeIt = m_types.find( structure.first );
1161     assert( typeIt != m_types.end() );
1162     checkForError(
1163       !typeIt->second.referencedIn.empty(), structure.second.xmlLine, "structure <" + structure.first + "> not listed in any feature or extension" );
1164 
1165     // check for existence of all structs that are extended by this struct
1166     for ( auto const & extend : structure.second.structExtends )
1167     {
1168       checkForError( ( m_structures.find( extend ) != m_structures.end() ) || ( m_structureAliases.find( extend ) != m_structureAliases.end() ),
1169                      structure.second.xmlLine,
1170                      "struct <" + structure.first + "> extends unknown <" + extend + ">" );
1171     }
1172 
1173     // checks on the members of a struct
1174     checkStructMemberCorrectness( structure.first, structure.second.members, sTypeValues );
1175   }
1176 
1177   // enum VkStructureType checks (need to be after structure checks because of sTypeValues gathered there)
1178   auto structureTypeIt = m_enums.find( "VkStructureType" );
1179   assert( structureTypeIt != m_enums.end() );
1180   for ( auto const & enumValue : structureTypeIt->second.values )
1181   {
1182     if ( ( enumValue.name == "VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO" ) || ( enumValue.name == "VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO" ) )
1183     {
1184       checkForError(
1185         sTypeValues.find( enumValue.name ) == sTypeValues.end(), enumValue.xmlLine, "Reserved VkStructureType enum value <" + enumValue.name + "> is used" );
1186     }
1187     else
1188     {
1189       checkForError( sTypeValues.erase( enumValue.name ) == 1, enumValue.xmlLine, "VkStructureType enum value <" + enumValue.name + "> never used" );
1190     }
1191   }
1192   assert( sTypeValues.empty() );
1193 }
1194 
checkStructMemberCorrectness(std::string const & structureName,std::vector<MemberData> const & members,std::set<std::string> & sTypeValues) const1195 void VulkanHppGenerator::checkStructMemberCorrectness( std::string const &             structureName,
1196                                                        std::vector<MemberData> const & members,
1197                                                        std::set<std::string> &         sTypeValues ) const
1198 {
1199   for ( auto const & member : members )
1200   {
1201     // check that all member types are required in some feature or extension
1202     if ( member.type.type.starts_with( "Vk" ) )
1203     {
1204       auto typeIt = m_types.find( member.type.type );
1205       assert( typeIt != m_types.end() );
1206       checkForError( !typeIt->second.referencedIn.empty(),
1207                      member.xmlLine,
1208                      "struct member type <" + member.type.type + "> used in struct <" + structureName + "> is never listed for any feature or extension" );
1209     }
1210 
1211     // if a member specifies a selector, that member is a union and the selector is an enum
1212     // check that there's a 1-1 connection between the specified selections and the values of that enum
1213     if ( !member.selector.empty() )
1214     {
1215       auto selectorIt = findStructMemberIt( member.selector, members );
1216       assert( selectorIt != members.end() );
1217       auto selectorEnumIt = m_enums.find( selectorIt->type.type );
1218       assert( selectorEnumIt != m_enums.end() );
1219       auto unionIt = m_structures.find( member.type.type );
1220       assert( ( unionIt != m_structures.end() ) && unionIt->second.isUnion );
1221       for ( auto const & unionMember : unionIt->second.members )
1222       {
1223         // check that each union member has a selection, that is a value of the seleting enum
1224         assert( !unionMember.selection.empty() );
1225         for ( auto const & selection : unionMember.selection )
1226         {
1227           checkForError( std::find_if( selectorEnumIt->second.values.begin(),
1228                                        selectorEnumIt->second.values.end(),
1229                                        [&selection]( EnumValueData const & evd ) { return evd.name == selection; } ) != selectorEnumIt->second.values.end(),
1230                          unionMember.xmlLine,
1231                          "union member <" + unionMember.name + "> uses selection <" + selection + "> that is not part of the selector type <" +
1232                            selectorIt->type.type + ">" );
1233         }
1234       }
1235     }
1236 
1237     // check that each member type is known
1238     checkForError( m_types.find( member.type.type ) != m_types.end(), member.xmlLine, "struct member uses unknown type <" + member.type.type + ">" );
1239 
1240     // check that any used constant is a known constant
1241     if ( !member.usedConstant.empty() )
1242     {
1243       checkForError( m_constants.find( member.usedConstant ) != m_constants.end(),
1244                      member.xmlLine,
1245                      "struct member array size uses unknown constant <" + member.usedConstant + ">" );
1246     }
1247 
1248     // checks if a value is specified
1249     if ( !member.value.empty() )
1250     {
1251       auto enumIt = m_enums.find( member.type.type );
1252       if ( enumIt != m_enums.end() )
1253       {
1254         // check that the value exists in the specified enum
1255         checkForError( std::find_if( enumIt->second.values.begin(),
1256                                      enumIt->second.values.end(),
1257                                      [&member]( auto const & evd ) { return member.value == evd.name; } ) != enumIt->second.values.end(),
1258                        member.xmlLine,
1259                        "value <" + member.value + "> for member <" + member.name + "> in structure <" + structureName + "> of enum type <" + member.type.type +
1260                          "> not listed" );
1261         // special handling for sType: no value should appear more than once
1262         if ( member.name == "sType" )
1263         {
1264           checkForError( sTypeValues.insert( member.value ).second, member.xmlLine, "sType value <" + member.value + "> has been used before" );
1265         }
1266       }
1267       else if ( member.type.type == "uint32_t" )
1268       {
1269         // check that a value for a uint32_t is all digits
1270         checkForError( member.value.find_first_not_of( "0123456789" ) == std::string::npos,
1271                        member.xmlLine,
1272                        "value <" + member.value + "> for member <" + member.name + "> in structure <" + structureName + "> of type <" + member.type.type +
1273                          "> is not a number" );
1274       }
1275       else
1276       {
1277         // don't know the type of the value -> error out
1278         checkForError( false,
1279                        member.xmlLine,
1280                        "member <" + member.name + "> in structure <" + structureName + "> holds value <" + member.value + "> for an unhandled type <" +
1281                          member.type.type + ">" );
1282       }
1283     }
1284   }
1285 }
1286 
combineDataTypes(std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,bool enumerating,std::vector<std::string> const & dataTypes,CommandFlavourFlags flavourFlags,bool raii) const1287 std::string VulkanHppGenerator::combineDataTypes( std::map<size_t, VectorParamData> const & vectorParams,
1288                                                   std::vector<size_t> const &               returnParams,
1289                                                   bool                                      enumerating,
1290                                                   std::vector<std::string> const &          dataTypes,
1291                                                   CommandFlavourFlags                       flavourFlags,
1292                                                   bool                                      raii ) const
1293 {
1294   assert( dataTypes.size() == returnParams.size() );
1295 
1296   std::vector<std::string> modifiedDataTypes( dataTypes.size() );
1297   for ( size_t i = 0; i < returnParams.size(); ++i )
1298   {
1299     auto vectorParamIt   = vectorParams.find( returnParams[i] );
1300     modifiedDataTypes[i] = ( vectorParamIt == vectorParams.end() || ( flavourFlags & CommandFlavourFlagBits::singular ) )
1301                            ? dataTypes[i]
1302                            : ( "std::vector<" + dataTypes[i] +
1303                                ( raii || ( flavourFlags & CommandFlavourFlagBits::unique )
1304                                    ? ">"
1305                                    : ( ", " + startUpperCase( stripPrefix( dataTypes[i], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator>" ) ) );
1306   }
1307 
1308   std::string combinedType;
1309   switch ( modifiedDataTypes.size() )
1310   {
1311     case 0: combinedType = "void"; break;
1312     case 1: combinedType = modifiedDataTypes[0]; break;
1313     case 2:
1314       assert( !enumerating || ( ( vectorParams.find( returnParams[1] ) != vectorParams.end() ) &&
1315                                 ( vectorParams.find( returnParams[1] )->second.lenParam == returnParams[0] ) ) );
1316       combinedType = enumerating ? modifiedDataTypes[1] : ( "std::pair<" + modifiedDataTypes[0] + ", " + modifiedDataTypes[1] + ">" );
1317       break;
1318     case 3:
1319       assert( enumerating && ( vectorParams.size() == 2 ) && ( vectorParams.begin()->first == returnParams[1] ) &&
1320               ( vectorParams.begin()->second.lenParam == returnParams[0] ) && ( std::next( vectorParams.begin() )->first == returnParams[2] ) &&
1321               ( std::next( vectorParams.begin() )->second.lenParam == returnParams[0] ) );
1322       combinedType = "std::pair<" + modifiedDataTypes[1] + ", " + modifiedDataTypes[2] + ">";
1323       break;
1324     default: assert( false ); break;
1325   }
1326   return combinedType;
1327 }
1328 
containsArray(std::string const & type) const1329 bool VulkanHppGenerator::containsArray( std::string const & type ) const
1330 {
1331   // a simple recursive check if a type is or contains an array
1332   auto structureIt = m_structures.find( type );
1333   bool found       = false;
1334   if ( structureIt != m_structures.end() )
1335   {
1336     for ( auto memberIt = structureIt->second.members.begin(); memberIt != structureIt->second.members.end() && !found; ++memberIt )
1337     {
1338       found = !memberIt->arraySizes.empty() || containsArray( memberIt->type.type );
1339     }
1340   }
1341   return found;
1342 }
1343 
containsFuncPointer(std::string const & type) const1344 bool VulkanHppGenerator::containsFuncPointer( std::string const & type ) const
1345 {
1346   // a simple recursive check if a type contains a funcpointer
1347   auto structureIt = m_structures.find( type );
1348   bool found       = false;
1349   if ( structureIt != m_structures.end() )
1350   {
1351     for ( auto memberIt = structureIt->second.members.begin(); memberIt != structureIt->second.members.end() && !found; ++memberIt )
1352     {
1353       found = ( m_funcPointers.find( memberIt->type.type ) != m_funcPointers.end() ) ||
1354               ( ( memberIt->type.type != type ) && containsFuncPointer( memberIt->type.type ) );
1355     }
1356   }
1357   return found;
1358 }
1359 
containsFloatingPoints(std::vector<MemberData> const & members) const1360 bool VulkanHppGenerator::containsFloatingPoints( std::vector<MemberData> const & members ) const
1361 {
1362   for ( auto const & m : members )
1363   {
1364     if ( ( ( m.type.type == "float" ) || ( m.type.type == "double" ) ) && m.type.isValue() )
1365     {
1366       return true;
1367     }
1368   }
1369   return false;
1370 }
1371 
containsUnion(std::string const & type) const1372 bool VulkanHppGenerator::containsUnion( std::string const & type ) const
1373 {
1374   // a simple recursive check if a type is or contains a union
1375   auto structureIt = m_structures.find( type );
1376   bool found       = false;
1377   if ( structureIt != m_structures.end() )
1378   {
1379     found = structureIt->second.isUnion;
1380     for ( auto memberIt = structureIt->second.members.begin(); memberIt != structureIt->second.members.end() && !found; ++memberIt )
1381     {
1382       found = memberIt->type.isValue() && containsUnion( memberIt->type.type );
1383     }
1384   }
1385   return found;
1386 }
1387 
determineConstPointerParams(std::vector<ParamData> const & params) const1388 std::vector<size_t> VulkanHppGenerator::determineConstPointerParams( std::vector<ParamData> const & params ) const
1389 {
1390   std::vector<size_t> constPointerParams;
1391 
1392   for ( size_t i = 0; i < params.size(); i++ )
1393   {
1394     // very special handling for some types, which come in as non-const pointers, but are meant as const-pointers
1395     if ( params[i].type.isConstPointer() ||
1396          ( params[i].type.isNonConstPointer() && ( specialPointerTypes.find( params[i].type.type ) != specialPointerTypes.end() ) ) )
1397     {
1398       constPointerParams.push_back( i );
1399     }
1400   }
1401   return constPointerParams;
1402 }
1403 
determineDataTypes(std::vector<VulkanHppGenerator::ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,std::set<size_t> const & templatedParams) const1404 std::vector<std::string> VulkanHppGenerator::determineDataTypes( std::vector<VulkanHppGenerator::ParamData> const & params,
1405                                                                  std::map<size_t, VectorParamData> const &          vectorParams,
1406                                                                  std::vector<size_t> const &                        returnParams,
1407                                                                  std::set<size_t> const &                           templatedParams ) const
1408 {
1409   std::vector<std::string> dataTypes;
1410   for ( auto rp : returnParams )
1411   {
1412     if ( templatedParams.find( rp ) != templatedParams.end() )
1413     {
1414       auto vectorParamIt = vectorParams.find( rp );
1415       if ( ( vectorParamIt != vectorParams.end() ) && ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->first ) != returnParams.end() ) &&
1416            ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) != returnParams.end() ) )
1417       {
1418         dataTypes.push_back( "uint8_t" );
1419       }
1420       else
1421       {
1422         dataTypes.push_back( ( stripPrefix( params[rp].name, "p" ) + "Type" ) );
1423       }
1424     }
1425     else
1426     {
1427       dataTypes.push_back( trimEnd( stripPostfix( params[rp].type.compose( "VULKAN_HPP_NAMESPACE" ), "*" ) ) );
1428     }
1429   }
1430   return dataTypes;
1431 }
1432 
determineDefaultStartIndex(std::vector<ParamData> const & params,std::set<size_t> const & skippedParams) const1433 size_t VulkanHppGenerator::determineDefaultStartIndex( std::vector<ParamData> const & params, std::set<size_t> const & skippedParams ) const
1434 {
1435   // determine the index where the arguments start to have defaults
1436   size_t defaultStartIndex = INVALID_INDEX;
1437   for ( int i = static_cast<int>( params.size() ) - 1; ( 0 <= i ) && ( params[i].optional || ( skippedParams.find( i ) != skippedParams.end() ) ); --i )
1438   {
1439     defaultStartIndex = i;
1440   }
1441   return defaultStartIndex;
1442 }
1443 
determineEnumeration(std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams) const1444 bool VulkanHppGenerator::determineEnumeration( std::map<size_t, VectorParamData> const & vectorParams, std::vector<size_t> const & returnParams ) const
1445 {
1446   // a command is considered to be enumerating some data, if for at least one vectorParam both, the data and the counter, are returnParams
1447   return std::find_if( vectorParams.begin(),
1448                        vectorParams.end(),
1449                        [&returnParams]( auto const & vp )
1450                        {
1451                          return std::find( returnParams.begin(), returnParams.end(), vp.first ) != returnParams.end() &&
1452                                 std::find( returnParams.begin(), returnParams.end(), vp.second.lenParam ) != returnParams.end();
1453                        } ) != vectorParams.end();
1454 }
1455 
determineInitialSkipCount(std::string const & command) const1456 size_t VulkanHppGenerator::determineInitialSkipCount( std::string const & command ) const
1457 {
1458   // determine the number of arguments to skip for a function
1459   // -> 0: the command is not bound to an instance or a device (the corresponding handle has no name)
1460   // -> 1: the command bound to an instance or a device (the corresponding handle has a name)
1461   // -> 2: the command has been moved to a second handle
1462   auto commandIt = m_commands.find( command );
1463   assert( commandIt != m_commands.end() );
1464   auto handleIt = m_handles.find( commandIt->second.handle );
1465   assert( handleIt != m_handles.end() );
1466   if ( handleIt->second.commands.find( command ) == handleIt->second.commands.end() )
1467   {
1468     assert( 1 < commandIt->second.params.size() );
1469     assert( m_handles.find( commandIt->second.params[1].type.type ) != m_handles.end() );
1470     return 2;
1471   }
1472   else
1473   {
1474     return handleIt->first.empty() ? 0 : 1;
1475   }
1476 }
1477 
determineReturnParams(std::vector<ParamData> const & params) const1478 std::vector<size_t> VulkanHppGenerator::determineReturnParams( std::vector<ParamData> const & params ) const
1479 {
1480   std::vector<size_t> nonConstPointerParamIndices;
1481 
1482   for ( size_t i = 0; i < params.size(); i++ )
1483   {
1484     // very special handling of parameters of some types, which always come as a non-const pointer but are not meant
1485     // to be a potential return value!
1486     if ( params[i].type.isNonConstPointer() && ( specialPointerTypes.find( params[i].type.type ) == specialPointerTypes.end() ) )
1487     {
1488       nonConstPointerParamIndices.push_back( i );
1489     }
1490   }
1491   return nonConstPointerParamIndices;
1492 }
1493 
1494 std::vector<std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator>
determineRAIIHandleConstructors(std::string const & handleType,std::map<std::string,CommandData>::const_iterator destructorIt) const1495   VulkanHppGenerator::determineRAIIHandleConstructors( std::string const & handleType, std::map<std::string, CommandData>::const_iterator destructorIt ) const
1496 {
1497   std::vector<std::map<std::string, CommandData>::const_iterator> constructorIts;
1498   auto                                                            isConstructorCandidate = [&handleType]( std::pair<std::string, CommandData> const & cd )
1499   {
1500     return std::find_if( cd.second.params.begin(),
1501                          cd.second.params.end(),
1502                          [&handleType]( ParamData const & pd )
1503                          { return ( pd.type.type == handleType ) && pd.type.isNonConstPointer(); } ) != cd.second.params.end();
1504   };
1505   for ( auto commandIt = m_commands.begin(); commandIt != m_commands.end(); )
1506   {
1507     // find the commands that get a non-const pointer to the handleType, that is, return a handle type
1508     commandIt = std::find_if( commandIt, m_commands.end(), isConstructorCandidate );
1509     if ( commandIt != m_commands.end() )
1510     {
1511       // only commands that provide all information needed for the destructor can be considered a constructor!
1512       bool valid = true;
1513       if ( destructorIt != m_commands.end() )
1514       {
1515         // get the destructors parameter to the handleType
1516         auto desctructorHandleParamIt = std::find_if( destructorIt->second.params.begin(),
1517                                                       destructorIt->second.params.end(),
1518                                                       [&handleType]( ParamData const & pd ) { return pd.type.type == handleType; } );
1519         assert( desctructorHandleParamIt != destructorIt->second.params.end() );
1520 
1521         // lambda to check if a destructor parameter is a parameter of the constructor candidate
1522         // (or it's just the len parameter, which is not needed for the constructor)
1523         auto isConstructorCandidateParam = [&desctructorHandleParamIt, &commandIt, this]( ParamData const & destructorParam )
1524         {
1525           // check if the destructor param type equals this param type, or, if this param type is a struct, is part of
1526           // that struct
1527           auto isDestructorParamType = [&destructorParam, this]( ParamData const & pd )
1528           {
1529             if ( pd.type.type != destructorParam.type.type )
1530             {
1531               // check if the destructor param type equals a structure member type
1532               auto structureIt = m_structures.find( pd.type.type );
1533               return ( structureIt != m_structures.end() ) &&
1534                      ( findStructMemberItByType( destructorParam.type.type, structureIt->second.members ) != structureIt->second.members.end() );
1535             }
1536             return true;
1537           };
1538 
1539           return ( destructorParam.name == desctructorHandleParamIt->len ) ||
1540                  ( std::find_if( commandIt->second.params.begin(), commandIt->second.params.end(), isDestructorParamType ) != commandIt->second.params.end() );
1541         };
1542 
1543         // the constructor candidate is valid, if none of the (relevant) destructor parameters is missing in the
1544         // constructor candidate params
1545         valid = ( std::find_if_not( destructorIt->second.params.begin(), destructorIt->second.params.end(), isConstructorCandidateParam ) ==
1546                   destructorIt->second.params.end() );
1547       }
1548       if ( valid )
1549       {
1550         // filter out alias functions
1551         if ( commandIt->second.alias.empty() )
1552         {
1553           constructorIts.push_back( commandIt );
1554         }
1555       }
1556       ++commandIt;
1557     }
1558   }
1559   assert( !constructorIts.empty() );
1560   return constructorIts;
1561 }
1562 
determineRAIIHandleDestructor(std::string const & handleType) const1563 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator VulkanHppGenerator::determineRAIIHandleDestructor( std::string const & handleType ) const
1564 {
1565   std::string type         = stripPrefix( handleType, "Vk" );
1566   auto        destructorIt = m_commands.find( "vkDestroy" + type );
1567   if ( destructorIt == m_commands.end() )
1568   {
1569     destructorIt = m_commands.find( "vkFree" + type + "s" );
1570     if ( destructorIt == m_commands.end() )
1571     {
1572       destructorIt = m_commands.find( "vkRelease" + type );
1573       if ( destructorIt == m_commands.end() )
1574       {
1575         if ( handleType == "VkDeviceMemory" )
1576         {
1577           // special handling for vkDeviceMemory
1578           destructorIt = m_commands.find( "vkFreeMemory" );
1579           assert( destructorIt != m_commands.end() );
1580         }
1581         else if ( handleType == "VkDisplayKHR" )
1582         {
1583           // special handling for VkDisplayKHR
1584           destructorIt = m_commands.find( "vkReleaseDisplayEXT" );
1585           assert( destructorIt != m_commands.end() );
1586         }
1587         else
1588         {
1589           assert( ( handleType == "VkDisplayModeKHR" ) || ( handleType == "VkPhysicalDevice" ) || ( handleType == "VkQueue" ) );
1590         }
1591       }
1592     }
1593   }
1594   return destructorIt;
1595 }
1596 
determineSingularParams(size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const1597 std::set<size_t> VulkanHppGenerator::determineSingularParams( size_t returnParam, std::map<size_t, VectorParamData> const & vectorParams ) const
1598 {
1599   auto returnVectorIt = vectorParams.find( returnParam );
1600   assert( returnVectorIt != vectorParams.end() );
1601   std::set<size_t> singularParams;
1602   singularParams.insert( returnVectorIt->second.lenParam );
1603   for ( auto const & vpi : vectorParams )
1604   {
1605     if ( vpi.second.lenParam == returnVectorIt->second.lenParam )
1606     {
1607       singularParams.insert( vpi.first );
1608     }
1609   }
1610   return singularParams;
1611 }
1612 
determineSkippedParams(std::vector<ParamData> const & params,size_t initialSkipCount,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,bool singular) const1613 std::set<size_t> VulkanHppGenerator::determineSkippedParams( std::vector<ParamData> const &            params,
1614                                                              size_t                                    initialSkipCount,
1615                                                              std::map<size_t, VectorParamData> const & vectorParams,
1616                                                              std::vector<size_t> const &               returnParams,
1617                                                              bool                                      singular ) const
1618 {
1619   // skip the initial skips (get fed by the object)
1620   assert( initialSkipCount <= params.size() );
1621   std::set<size_t> skippedParams;
1622   for ( size_t i = 0; i < initialSkipCount; ++i )
1623   {
1624     skippedParams.insert( i );
1625   }
1626 
1627   // skip the size parameters (get derived from an array), and a stride parameter
1628   for ( auto const & vpi : vectorParams )
1629   {
1630     assert( !params[vpi.first].len.empty() );
1631     if ( ( ( std::find_if( returnParams.begin(), returnParams.end(), [&vpi]( size_t rpi ) { return vpi.first == rpi; } ) == returnParams.end() ) &&
1632            isParam( params[vpi.first].len, params ) ) ||
1633          ( singular && params[vpi.second.lenParam].type.isValue() ) )
1634     {
1635       skippedParams.insert( vpi.second.lenParam );
1636     }
1637     if ( vpi.second.strideParam != INVALID_INDEX )
1638     {
1639       skippedParams.insert( vpi.second.strideParam );
1640     }
1641   }
1642 
1643   // skip the return parameters (get resolved by local variables to be returned)
1644   skippedParams.insert( returnParams.begin(), returnParams.end() );
1645 
1646   return skippedParams;
1647 }
1648 
determineSubStruct(std::pair<std::string,StructureData> const & structure) const1649 std::string VulkanHppGenerator::determineSubStruct( std::pair<std::string, StructureData> const & structure ) const
1650 {
1651   if ( structure.second.members.front().name != "sType" )
1652   {
1653     // check if sd is a substruct of structure
1654     auto isSubStruct = [&structure]( std::pair<std::string, StructureData> const & sd )
1655     {
1656       // member-by-member comparison of type and name
1657       auto memberIt = structure.second.members.begin();
1658       auto isMember = [&memberIt]( MemberData const & md )
1659       {
1660         if ( ( md.type == memberIt->type ) && ( md.name == memberIt->name ) )
1661         {
1662           ++memberIt;
1663           return true;
1664         }
1665         return false;
1666       };
1667 
1668       return ( sd.second.members.size() < structure.second.members.size() ) &&
1669              ( std::find_if_not( sd.second.members.begin(), sd.second.members.end(), isMember ) == sd.second.members.end() );
1670     };
1671 
1672     // look for a struct in m_structures that starts identically to structure
1673     auto structIt = std::find_if( m_structures.begin(), m_structures.end(), isSubStruct );
1674     return ( structIt == m_structures.end() ) ? "" : structIt->first;
1675   }
1676   return "";
1677 }
1678 
determineVectorParams(std::vector<ParamData> const & params) const1679 std::map<size_t, VulkanHppGenerator::VectorParamData> VulkanHppGenerator::determineVectorParams( std::vector<ParamData> const & params ) const
1680 {
1681   std::map<size_t, VectorParamData> vectorParams;
1682 
1683   // look for the parameters whose len equals the name of an other parameter
1684   for ( size_t i = 0; i < params.size(); i++ )
1685   {
1686     if ( !params[i].len.empty() && ( params[i].len != "null-terminated" ) )
1687     {
1688       VectorParamData & vpd = vectorParams[i];
1689 
1690       std::string len;
1691       if ( altLens.find( params[i].len ) != altLens.end() )
1692       {
1693         checkForError( params[i].len == "(samples + 31) / 32", params[i].xmlLine, "unknown command parameter len <" + params[i].len + ">" );
1694         len = "samples";
1695       }
1696       else
1697       {
1698         len = params[i].len;
1699       }
1700       auto lenIt =
1701         std::find_if( params.begin(), params.end(), [&len, this]( auto const & pd ) { return ( len == pd.name ) || isLenByStructMember( len, pd ); } );
1702       assert( lenIt != params.end() );
1703       vpd.lenParam = std::distance( params.begin(), lenIt );
1704       if ( !params[i].stride.empty() )
1705       {
1706         std::string const & stride   = params[i].stride;
1707         auto                strideIt = std::find_if( params.begin(), params.end(), [&stride]( auto const & pd ) { return stride == pd.name; } );
1708         assert( strideIt != params.end() );
1709         vpd.strideParam = std::distance( params.begin(), strideIt );
1710       }
1711     }
1712   }
1713   return vectorParams;
1714 }
1715 
determineVoidPointerParams(std::vector<ParamData> const & params) const1716 std::set<size_t> VulkanHppGenerator::determineVoidPointerParams( std::vector<ParamData> const & params ) const
1717 {
1718   std::set<size_t> voidPointerParams;
1719 
1720   for ( size_t i = 0; i < params.size(); i++ )
1721   {
1722     if ( !params[i].type.isValue() && ( params[i].type.type == "void" ) && ( params[i].type.postfix != "**" ) )
1723     {
1724       voidPointerParams.insert( i );
1725     }
1726   }
1727   return voidPointerParams;
1728 }
1729 
distributeSecondLevelCommands(std::set<std::string> const & specialFunctions)1730 void VulkanHppGenerator::distributeSecondLevelCommands( std::set<std::string> const & specialFunctions )
1731 {
1732   // distribute commands from instance/device to second-level handles, like Queue, Event,... for RAII handles
1733   for ( auto & handle : m_handles )
1734   {
1735     if ( !handle.first.empty() )
1736     {
1737       for ( auto command = handle.second.commands.begin(); command != handle.second.commands.end(); )
1738       {
1739         bool foundCommand = false;
1740         if ( specialFunctions.find( *command ) == specialFunctions.end() )
1741         {
1742           auto commandIt = m_commands.find( *command );
1743           assert( commandIt != m_commands.end() );
1744           assert( commandIt->second.params.front().type.type == handle.first );
1745           if ( ( 1 < commandIt->second.params.size() ) && ( isHandleType( commandIt->second.params[1].type.type ) ) && !commandIt->second.params[1].optional )
1746           {
1747             auto handleIt = m_handles.find( commandIt->second.params[1].type.type );
1748             assert( handleIt != m_handles.end() );
1749             // filter out functions seem to fit due to taking handles as first and second argument, but the first argument is not the
1750             // type to create the second one, and so it's unknown to the raii handle!
1751             assert( !handleIt->second.constructorIts.empty() );
1752             if ( ( *handleIt->second.constructorIts.begin() )->second.handle == handle.first )
1753             {
1754               assert( std::find_if( handleIt->second.constructorIts.begin(),
1755                                     handleIt->second.constructorIts.end(),
1756                                     [&handle]( auto const & constructorIt )
1757                                     { return constructorIt->second.handle != handle.first; } ) == handleIt->second.constructorIts.end() );
1758               handleIt->second.secondLevelCommands.insert( *command );
1759               command      = handle.second.commands.erase( command );
1760               foundCommand = true;
1761             }
1762           }
1763         }
1764         if ( !foundCommand )
1765         {
1766           ++command;
1767         }
1768       }
1769     }
1770   }
1771 }
1772 
findBaseName(std::string aliasName,std::map<std::string,EnumAliasData> const & aliases) const1773 std::string VulkanHppGenerator::findBaseName( std::string aliasName, std::map<std::string, EnumAliasData> const & aliases ) const
1774 {
1775   std::string baseName = aliasName;
1776   auto        aliasIt  = aliases.find( baseName );
1777   while ( aliasIt != aliases.end() )
1778   {
1779     baseName = aliasIt->second.name;
1780     aliasIt  = aliases.find( baseName );
1781   }
1782   return baseName;
1783 }
1784 
findStructMemberIt(std::string const & name,std::vector<MemberData> const & memberData) const1785 std::vector<VulkanHppGenerator::MemberData>::const_iterator VulkanHppGenerator::findStructMemberIt( std::string const &             name,
1786                                                                                                     std::vector<MemberData> const & memberData ) const
1787 {
1788   return std::find_if( memberData.begin(), memberData.end(), [&name]( MemberData const & md ) { return md.name == name; } );
1789 }
1790 
findStructMemberItByType(std::string const & type,std::vector<MemberData> const & memberData) const1791 std::vector<VulkanHppGenerator::MemberData>::const_iterator VulkanHppGenerator::findStructMemberItByType( std::string const &             type,
1792                                                                                                           std::vector<MemberData> const & memberData ) const
1793 {
1794   return std::find_if( memberData.begin(), memberData.end(), [&type]( MemberData const & md ) { return md.type.type == type; } );
1795 }
1796 
generateAllocatorTemplates(std::vector<size_t> const & returnParams,std::vector<std::string> const & returnDataTypes,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool definition) const1797 std::pair<std::string, std::string> VulkanHppGenerator::generateAllocatorTemplates( std::vector<size_t> const &               returnParams,
1798                                                                                     std::vector<std::string> const &          returnDataTypes,
1799                                                                                     std::map<size_t, VectorParamData> const & vectorParams,
1800                                                                                     CommandFlavourFlags                       flavourFlags,
1801                                                                                     bool                                      definition ) const
1802 {
1803   bool chained  = flavourFlags & CommandFlavourFlagBits::chained;
1804   bool singular = flavourFlags & CommandFlavourFlagBits::singular;
1805   bool unique   = flavourFlags & CommandFlavourFlagBits::unique;
1806 
1807   assert( returnParams.size() == returnDataTypes.size() );
1808   std::string allocatorTemplates;
1809   if ( !singular )
1810   {
1811     for ( size_t i = 0; i < returnParams.size(); i++ )
1812     {
1813       if ( vectorParams.find( returnParams[i] ) != vectorParams.end() )
1814       {
1815         if ( chained )
1816         {
1817           allocatorTemplates += "typename StructureChainAllocator";
1818           if ( !definition )
1819           {
1820             allocatorTemplates += " = std::allocator<StructureChain>";
1821           }
1822         }
1823         else
1824         {
1825           allocatorTemplates += "typename " + startUpperCase( stripPrefix( returnDataTypes[i], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator";
1826           if ( !definition )
1827           {
1828             allocatorTemplates += " = std::allocator<" + ( unique ? ( "UniqueHandle<" + returnDataTypes[i] + ", Dispatch>" ) : returnDataTypes[i] ) + ">";
1829           }
1830         }
1831         allocatorTemplates += ", ";
1832       }
1833     }
1834   }
1835   std::string uniqueHandleAllocatorTemplates;
1836   if ( unique && !allocatorTemplates.empty() )
1837   {
1838     uniqueHandleAllocatorTemplates = ", " + stripPostfix( allocatorTemplates, ", " );
1839     allocatorTemplates.clear();
1840   }
1841   return std::make_pair( allocatorTemplates, uniqueHandleAllocatorTemplates );
1842 }
1843 
generateArgumentListEnhanced(std::vector<ParamData> const & params,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & skippedParams,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams,bool definition,CommandFlavourFlags flavourFlags,bool withDispatcher) const1844 std::string VulkanHppGenerator::generateArgumentListEnhanced( std::vector<ParamData> const &            params,
1845                                                               std::vector<size_t> const &               returnParams,
1846                                                               std::map<size_t, VectorParamData> const & vectorParams,
1847                                                               std::set<size_t> const &                  skippedParams,
1848                                                               std::set<size_t> const &                  singularParams,
1849                                                               std::set<size_t> const &                  templatedParams,
1850                                                               bool                                      definition,
1851                                                               CommandFlavourFlags                       flavourFlags,
1852                                                               bool                                      withDispatcher ) const
1853 {
1854   bool withAllocators = flavourFlags & CommandFlavourFlagBits::withAllocator;
1855 
1856   size_t defaultStartIndex = withAllocators ? ~0 : determineDefaultStartIndex( params, skippedParams );
1857 
1858   std::string argumentList;
1859   bool        encounteredArgument = false;
1860   for ( size_t i = 0; i < params.size(); ++i )
1861   {
1862     if ( skippedParams.find( i ) == skippedParams.end() )
1863     {
1864       if ( encounteredArgument )
1865       {
1866         argumentList += ", ";
1867       }
1868       bool hasDefaultAssignment = false;
1869 
1870       std::string composedType = params[i].type.compose( "VULKAN_HPP_NAMESPACE" );
1871 
1872       if ( singularParams.find( i ) != singularParams.end() )
1873       {
1874         assert( !params[i].optional );
1875         assert( params[i].type.isConstPointer() && !params[i].len.empty() && !isLenByStructMember( params[i].len, params ) &&
1876                 params[i].type.type.starts_with( "Vk" ) );
1877         assert( !isHandleType( params[i].type.type ) );
1878         assert( composedType.ends_with( " *" ) );
1879         argumentList += stripPostfix( composedType, " *" ) + " & " + stripPluralS( startLowerCase( stripPrefix( params[i].name, "p" ) ), m_tags );
1880       }
1881       else if ( params[i].type.isConstPointer() )
1882       {
1883         assert( composedType.ends_with( " *" ) );
1884         std::string name = startLowerCase( stripPrefix( params[i].name, "p" ) );
1885         if ( params[i].len.empty() )
1886         {
1887           assert( withDispatcher || !isHandleType( params[i].type.type ) );
1888           assert( !params[i].type.prefix.empty() && ( params[i].type.postfix == "*" ) );
1889           assert( params[i].arraySizes.empty() );
1890           if ( params[i].type.type == "void" )
1891           {
1892             argumentList += ( templatedParams.find( i ) == templatedParams.end() ) ? ( composedType + " " + params[i].name )
1893                                                                                    : ( stripPrefix( params[i].name, "p" ) + "Type const & " + name );
1894           }
1895           else if ( params[i].optional )
1896           {
1897             argumentList += "Optional<" + stripPostfix( composedType, " *" ) + "> " + name +
1898                             ( ( definition || withAllocators ) ? "" : " VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT" );
1899             hasDefaultAssignment = true;
1900           }
1901           else
1902           {
1903             argumentList += stripPostfix( composedType, " *" ) + " & " + name;
1904           }
1905         }
1906         else
1907         {
1908           // a const-pointer with a non-empty len is either null-terminated (aka a string) or represented by an
1909           // ArrayProxy
1910           assert( params[i].arraySizes.empty() );
1911           if ( params[i].len == "null-terminated" )
1912           {
1913             assert( params[i].type.type == "char" );
1914             if ( params[i].optional )
1915             {
1916               argumentList +=
1917                 "Optional<const std::string> " + name + ( ( definition || withAllocators ) ? "" : " VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT" );
1918               hasDefaultAssignment = true;
1919             }
1920             else
1921             {
1922               argumentList += "const std::string & " + name;
1923             }
1924           }
1925           else
1926           {
1927             // an ArrayProxy also covers no data, so any optional flag can be ignored here
1928             std::string type = stripPostfix( composedType, " *" );
1929             size_t      pos  = type.find( "void" );
1930             if ( pos != std::string::npos )
1931             {
1932               type.replace( pos, 4, stripPrefix( params[i].name, "p" ) + "Type" );
1933             }
1934             argumentList +=
1935               std::string( "VULKAN_HPP_NAMESPACE::" ) + ( params[i].stride.empty() ? "" : "Strided" ) + "ArrayProxy<" + type + "> const & " + name;
1936             if ( params[i].optional && !definition )
1937             {
1938               assert( params[i].stride.empty() );
1939               argumentList += " VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT";
1940               hasDefaultAssignment = true;
1941             }
1942           }
1943         }
1944       }
1945       else if ( params[i].type.isNonConstPointer() )
1946       {
1947         assert( withDispatcher || !isHandleType( params[i].type.type ) );
1948         assert( params[i].len.empty() && !params[i].optional );
1949         assert( composedType.ends_with( " *" ) );
1950         argumentList += stripPostfix( composedType, " *" ) + " & " + params[i].name;
1951       }
1952       else
1953       {
1954         assert( params[i].type.isValue() );
1955         argumentList += composedType + " " + params[i].name + generateCArraySizes( params[i].arraySizes );
1956       }
1957       argumentList += std::string( !definition && ( defaultStartIndex <= i ) && !hasDefaultAssignment ? " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT" : "" );
1958       encounteredArgument = true;
1959     }
1960   }
1961   if ( withAllocators )
1962   {
1963     if ( flavourFlags & CommandFlavourFlagBits::chained )
1964     {
1965       if ( encounteredArgument )
1966       {
1967         argumentList += ", ";
1968       }
1969       argumentList += "StructureChainAllocator & structureChainAllocator";
1970       encounteredArgument = true;
1971     }
1972     else
1973     {
1974       for ( auto sp : skippedParams )
1975       {
1976         if ( !params[sp].len.empty() )
1977         {
1978           if ( encounteredArgument )
1979           {
1980             argumentList += ", ";
1981           }
1982           std::string type;
1983           if ( templatedParams.find( sp ) != templatedParams.end() )
1984           {
1985             auto vectorParamIt = vectorParams.find( sp );
1986             if ( ( vectorParamIt != vectorParams.end() ) &&
1987                  ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->first ) != returnParams.end() ) &&
1988                  ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) != returnParams.end() ) )
1989             {
1990               type = "Uint8_t";
1991             }
1992             else
1993             {
1994               type = stripPrefix( params[sp].name, "p" ) + "Type";
1995             }
1996           }
1997           else
1998           {
1999             type = ( params[sp].type.type == "void" ) ? "Uint8_t" : startUpperCase( stripPrefix( params[sp].type.type, "Vk" ) );
2000           }
2001           argumentList += type + "Allocator & " + startLowerCase( type ) + "Allocator";
2002           encounteredArgument = true;
2003         }
2004       }
2005     }
2006   }
2007   if ( withDispatcher )
2008   {
2009     if ( encounteredArgument )
2010     {
2011       argumentList += ", ";
2012     }
2013     argumentList += std::string( "Dispatch const & d" ) + ( definition ? "" : " VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT" );
2014   }
2015   return argumentList;
2016 }
2017 
generateArgumentListStandard(std::vector<ParamData> const & params,std::set<size_t> const & skippedParams) const2018 std::string VulkanHppGenerator::generateArgumentListStandard( std::vector<ParamData> const & params, std::set<size_t> const & skippedParams ) const
2019 {
2020   std::string argumentList;
2021   for ( size_t i = 0; i < params.size(); ++i )
2022   {
2023     if ( skippedParams.find( i ) == skippedParams.end() )
2024     {
2025       argumentList += params[i].type.compose( "VULKAN_HPP_NAMESPACE" ) + " " + params[i].name + generateCArraySizes( params[i].arraySizes ) + ", ";
2026     }
2027   }
2028   argumentList += "Dispatch const & d ";
2029   return argumentList;
2030 }
2031 
generateArgumentTemplates(std::vector<ParamData> const & params,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool raii) const2032 std::string VulkanHppGenerator::generateArgumentTemplates( std::vector<ParamData> const &            params,
2033                                                            std::vector<size_t> const &               returnParams,
2034                                                            std::map<size_t, VectorParamData> const & vectorParams,
2035                                                            std::set<size_t> const &                  templatedParams,
2036                                                            CommandFlavourFlags                       flavourFlags,
2037                                                            bool                                      raii ) const
2038 {
2039   std::string argumentTemplates;
2040   if ( !templatedParams.empty() )
2041   {
2042     assert( !( flavourFlags & CommandFlavourFlagBits::chained ) );
2043     for ( auto t : templatedParams )
2044     {
2045       assert( params[t].name.starts_with( "p" ) );
2046       auto vectorParamIt = vectorParams.find( t );
2047       if ( ( vectorParamIt == vectorParams.end() ) || ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->first ) == returnParams.end() ) ||
2048            ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) == returnParams.end() ) )
2049       {
2050         // only templated parameters that are not part of an enumeration are really templated
2051         argumentTemplates += "typename " + stripPrefix( params[t].name, "p" ) + "Type, ";
2052       }
2053     }
2054   }
2055   else if ( flavourFlags & CommandFlavourFlagBits::chained )
2056   {
2057     argumentTemplates = ( returnParams.size() == 1 ) ? "typename X, typename Y, typename... Z, " : "typename StructureChain, ";
2058   }
2059   if ( !argumentTemplates.empty() && raii )
2060   {
2061     argumentTemplates = "template <" + stripPostfix( argumentTemplates, ", " ) + ">";
2062   }
2063   return argumentTemplates;
2064 }
2065 
generateBaseTypes() const2066 std::string VulkanHppGenerator::generateBaseTypes() const
2067 {
2068   assert( !m_baseTypes.empty() );
2069   const std::string basetypesTemplate = R"(
2070   //==================
2071   //=== BASE TYPEs ===
2072   //==================
2073 
2074 ${basetypes}
2075 )";
2076 
2077   std::string basetypes;
2078   for ( auto const & baseType : m_baseTypes )
2079   {
2080     // filter out VkFlags and VkFlags64, as they are mapped to our own Flags class
2081     if ( ( baseType.first != "VkFlags" ) && ( baseType.first != "VkFlags64" ) )
2082     {
2083       basetypes += "  using " + stripPrefix( baseType.first, "Vk" ) + " = " + baseType.second.typeInfo.compose( "VULKAN_HPP_NAMESPACE" ) + ";\n";
2084     }
2085   }
2086 
2087   return replaceWithMap( basetypesTemplate, { { "basetypes", basetypes } } );
2088 }
2089 
generateBitmask(std::map<std::string,BitmaskData>::const_iterator bitmaskIt,std::string const & surroundingProtect) const2090 std::string VulkanHppGenerator::generateBitmask( std::map<std::string, BitmaskData>::const_iterator bitmaskIt, std::string const & surroundingProtect ) const
2091 {
2092   auto bitmaskBitsIt = m_enums.find( bitmaskIt->second.requirements );
2093   assert( bitmaskBitsIt != m_enums.end() );
2094 
2095   std::string bitmaskName = stripPrefix( bitmaskIt->first, "Vk" );
2096   std::string enumName    = stripPrefix( bitmaskBitsIt->first, "Vk" );
2097   std::string alias       = bitmaskIt->second.alias.empty() ? "" : ( "  using " + stripPrefix( bitmaskIt->second.alias, "Vk" ) + " = " + bitmaskName + ";\n" );
2098 
2099   std::string allFlags;
2100   if ( bitmaskBitsIt->second.values.empty() )
2101   {
2102     allFlags = " {};";
2103   }
2104   else
2105   {
2106     bool        encounteredFlag = false;
2107     std::string previousEnter, previousLeave;
2108     for ( auto const & value : bitmaskBitsIt->second.values )
2109     {
2110       // determine the values protect, if any
2111       std::string valueProtect = getProtect( value );
2112 
2113       // if the value's protect differs from the surrounding protect, generate protection code
2114       std::string enter, leave;
2115       if ( !valueProtect.empty() && ( valueProtect != surroundingProtect ) )
2116       {
2117         tie( enter, leave ) = generateProtection( valueProtect );
2118       }
2119       std::string valueName = generateEnumValueName( bitmaskBitsIt->first, value.name, true, m_tags );
2120       allFlags +=
2121         ( ( previousEnter != enter ) ? ( "\n" + previousLeave + enter ) : "\n" ) + "        " + ( encounteredFlag ? "| " : "  " ) + enumName + "::" + valueName;
2122       encounteredFlag = true;
2123       previousEnter   = enter;
2124       previousLeave   = leave;
2125     }
2126     if ( !previousLeave.empty() )
2127     {
2128       allFlags += "\n" + previousLeave;
2129     }
2130     allFlags += ";";
2131   }
2132 
2133   static const std::string bitmaskTemplate = R"(
2134   using ${bitmaskName} = Flags<${enumName}>;
2135 ${alias}
2136 
2137   template <> struct FlagTraits<${enumName}>
2138   {
2139     static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
2140     static VULKAN_HPP_CONST_OR_CONSTEXPR ${bitmaskName} allFlags = ${allFlags}
2141   };
2142 )";
2143 
2144   return replaceWithMap( bitmaskTemplate, { { "alias", alias }, { "allFlags", allFlags }, { "bitmaskName", bitmaskName }, { "enumName", enumName } } );
2145 }
2146 
generateBitmasksToString() const2147 std::string VulkanHppGenerator::generateBitmasksToString() const
2148 {
2149   const std::string bitmasksToStringTemplate = R"(
2150   //==========================
2151   //=== BITMASKs to_string ===
2152   //==========================
2153 
2154 ${bitmasksToString}
2155 )";
2156 
2157   std::string           bitmasksToString;
2158   std::set<std::string> listedBitmasks;
2159   for ( auto const & feature : m_features )
2160   {
2161     bitmasksToString += generateBitmasksToString( feature.second.requireData, listedBitmasks, feature.first );
2162   }
2163   for ( auto const & extIt : m_extensionsByNumber )
2164   {
2165     bitmasksToString += generateBitmasksToString( extIt.second->second.requireData, listedBitmasks, extIt.second->first );
2166   }
2167 
2168   return replaceWithMap( bitmasksToStringTemplate, { { "bitmasksToString", bitmasksToString } } );
2169 }
2170 
generateBitmasksToString(std::vector<RequireData> const & requireData,std::set<std::string> & listedBitmasks,std::string const & title) const2171 std::string VulkanHppGenerator::generateBitmasksToString( std::vector<RequireData> const & requireData,
2172                                                           std::set<std::string> &          listedBitmasks,
2173                                                           std::string const &              title ) const
2174 {
2175   std::string str;
2176   for ( auto const & require : requireData )
2177   {
2178     for ( auto const & type : require.types )
2179     {
2180       auto bitmaskIt = m_bitmasks.find( type );
2181       if ( ( bitmaskIt != m_bitmasks.end() ) && ( listedBitmasks.find( type ) == listedBitmasks.end() ) )
2182       {
2183         listedBitmasks.insert( type );
2184         str += generateBitmaskToString( bitmaskIt );
2185       }
2186     }
2187   }
2188   return addTitleAndProtection( title, str );
2189 }
2190 
generateBitmaskToString(std::map<std::string,BitmaskData>::const_iterator bitmaskIt) const2191 std::string VulkanHppGenerator::generateBitmaskToString( std::map<std::string, BitmaskData>::const_iterator bitmaskIt ) const
2192 {
2193   auto bitmaskBitsIt = m_enums.find( bitmaskIt->second.requirements );
2194   assert( bitmaskBitsIt != m_enums.end() );
2195 
2196   std::string bitmaskName = stripPrefix( bitmaskIt->first, "Vk" );
2197   std::string enumName    = stripPrefix( bitmaskBitsIt->first, "Vk" );
2198 
2199   std::string str;
2200   if ( bitmaskBitsIt->second.values.empty() )
2201   {
2202     static std::string bitmaskToStringTemplate = R"(
2203   VULKAN_HPP_INLINE std::string to_string( ${bitmaskName} )
2204   {
2205     return "{}";
2206   }
2207 )";
2208     str += replaceWithMap( bitmaskToStringTemplate, { { "bitmaskName", bitmaskName } } );
2209   }
2210   else
2211   {
2212     static const std::string bitmaskToStringTemplate = R"(
2213   VULKAN_HPP_INLINE std::string to_string( ${bitmaskName} value )
2214   {
2215     if ( !value )
2216       return "{}";
2217 
2218     std::string result;
2219 ${toStringChecks}
2220     return "{ " + result.substr( 0, result.size() - 3 ) + " }";
2221   }
2222 )";
2223 
2224     std::string toStringChecks;
2225     std::string previousEnter, previousLeave;
2226     for ( auto const & value : bitmaskBitsIt->second.values )
2227     {
2228       auto [enter, leave]   = generateProtection( getProtect( value ) );
2229       std::string valueName = generateEnumValueName( bitmaskBitsIt->first, value.name, true, m_tags );
2230       if ( value.singleBit )
2231       {
2232         toStringChecks += ( ( previousEnter != enter ) ? ( previousLeave + enter ) : "" ) + "    if ( value & " + enumName + "::" + valueName +
2233                           " ) result += \"" + valueName.substr( 1 ) + " | \";\n";
2234       }
2235       previousEnter = enter;
2236       previousLeave = leave;
2237     }
2238     if ( !previousLeave.empty() )
2239     {
2240       assert( previousLeave.ends_with( "\n" ) );
2241       toStringChecks += previousLeave;
2242       previousLeave.resize( previousLeave.size() - strlen( "\n" ) );
2243     }
2244 
2245     str += replaceWithMap( bitmaskToStringTemplate, { { "bitmaskName", bitmaskName }, { "toStringChecks", toStringChecks } } );
2246   }
2247 
2248   return str;
2249 }
2250 
generateCallArgumentsEnhanced(CommandData const & commandData,size_t initialSkipCount,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams,bool raiiHandleMemberFunction) const2251 std::string VulkanHppGenerator::generateCallArgumentsEnhanced( CommandData const &      commandData,
2252                                                                size_t                   initialSkipCount,
2253                                                                bool                     nonConstPointerAsNullptr,
2254                                                                std::set<size_t> const & singularParams,
2255                                                                std::set<size_t> const & templatedParams,
2256                                                                bool                     raiiHandleMemberFunction ) const
2257 {
2258   assert( initialSkipCount <= commandData.params.size() );
2259   std::string arguments;
2260   bool        encounteredArgument = false;
2261   if ( raiiHandleMemberFunction )
2262   {
2263     switch ( initialSkipCount )
2264     {
2265       case 1:
2266         assert( isHandleType( commandData.params[0].type.type ) && commandData.params[0].type.isValue() );
2267         assert( commandData.params[0].arraySizes.empty() && commandData.params[0].len.empty() );
2268         assert( commandData.params[0].type.type == commandData.handle );
2269         arguments           = "static_cast<" + commandData.handle + ">( m_" + startLowerCase( stripPrefix( commandData.handle, "Vk" ) ) + " )";
2270         encounteredArgument = true;
2271         break;
2272       case 2:
2273         {
2274           assert( isHandleType( commandData.params[0].type.type ) && commandData.params[0].type.isValue() );
2275           assert( commandData.params[0].arraySizes.empty() && commandData.params[0].len.empty() );
2276           assert( commandData.params[0].type.type == commandData.handle );
2277           auto handleIt = m_handles.find( commandData.params[1].type.type );
2278           assert( handleIt != m_handles.end() );
2279           arguments = "static_cast<" + commandData.handle + ">( m_" + startLowerCase( stripPrefix( commandData.handle, "Vk" ) ) + " )";
2280 
2281           assert( commandData.params[1].type.isValue() && commandData.params[1].arraySizes.empty() && commandData.params[1].len.empty() );
2282           arguments += ", static_cast<" + commandData.params[1].type.type + ">( m_" +
2283                        generateRAIIHandleConstructorParamName( handleIt->first, handleIt->second.destructorIt ) + " )";
2284           encounteredArgument = true;
2285         }
2286         break;
2287     }
2288   }
2289   else
2290   {
2291     for ( size_t i = 0; i < initialSkipCount; ++i )
2292     {
2293       if ( encounteredArgument )
2294       {
2295         arguments += ", ";
2296       }
2297       assert( isHandleType( commandData.params[i].type.type ) && commandData.params[i].type.isValue() );
2298       assert( commandData.params[i].arraySizes.empty() && commandData.params[i].len.empty() );
2299       arguments += "m_" + startLowerCase( stripPrefix( commandData.params[i].type.type, "Vk" ) );
2300       encounteredArgument = true;
2301     }
2302   }
2303   for ( size_t i = initialSkipCount; i < commandData.params.size(); ++i )
2304   {
2305     if ( encounteredArgument )
2306     {
2307       arguments += ", ";
2308     }
2309     arguments += generateCallArgumentEnhanced( commandData.params, i, nonConstPointerAsNullptr, singularParams, templatedParams );
2310     encounteredArgument = true;
2311   }
2312   return arguments;
2313 }
2314 
generateCallArgumentsRAIIFactory(std::vector<ParamData> const & params,size_t initialSkipCount,std::set<size_t> const & skippedParams,std::set<size_t> const & singularParams) const2315 std::string VulkanHppGenerator::generateCallArgumentsRAIIFactory( std::vector<ParamData> const & params,
2316                                                                   size_t                         initialSkipCount,
2317                                                                   std::set<size_t> const &       skippedParams,
2318                                                                   std::set<size_t> const &       singularParams ) const
2319 {
2320   assert( initialSkipCount <= params.size() );
2321   std::string arguments = "*this";
2322   // skip the last parameter!
2323   for ( size_t i = initialSkipCount; i < params.size() - 1; ++i )
2324   {
2325     if ( skippedParams.find( i ) == skippedParams.end() )
2326     {
2327       std::string argument = params[i].name;
2328       if ( !params[i].type.isValue() )
2329       {
2330         argument = startLowerCase( stripPrefix( argument, "p" ) );
2331         if ( singularParams.find( i ) != singularParams.end() )
2332         {
2333           argument = stripPluralS( argument, m_tags );
2334         }
2335       }
2336       else
2337       {
2338         assert( singularParams.find( i ) == singularParams.end() );
2339       }
2340       arguments += ", " + argument;
2341     }
2342   }
2343   return arguments;
2344 }
2345 
generateCallArgumentsStandard(std::string const & handle,std::vector<ParamData> const & params) const2346 std::string VulkanHppGenerator::generateCallArgumentsStandard( std::string const & handle, std::vector<ParamData> const & params ) const
2347 {
2348   std::string arguments;
2349   bool        encounteredArgument = false;
2350   for ( auto const & param : params )
2351   {
2352     if ( encounteredArgument )
2353     {
2354       arguments += ", ";
2355     }
2356     if ( ( param.type.type == handle ) && param.type.isValue() )
2357     {
2358       assert( param.arraySizes.empty() && param.len.empty() );
2359       arguments += "m_" + startLowerCase( stripPrefix( param.type.type, "Vk" ) );
2360     }
2361     else
2362     {
2363       std::string argument = param.name;
2364       if ( param.type.type.starts_with( "Vk" ) )
2365       {
2366         if ( !param.arraySizes.empty() )
2367         {
2368           assert( param.arraySizes.size() == 1 );
2369           assert( param.type.isValue() );
2370           assert( param.type.postfix.empty() );
2371           argument = "reinterpret_cast<" + param.type.compose( "" ) + " *>( " + argument + " )";
2372         }
2373         else if ( param.type.isValue() )
2374         {
2375           argument = "static_cast<" + param.type.type + ">( " + argument + " )";
2376         }
2377         else
2378         {
2379           assert( !param.type.postfix.empty() );
2380           argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2381         }
2382       }
2383       arguments += argument;
2384     }
2385     encounteredArgument = true;
2386   }
2387   return arguments;
2388 }
2389 
generateCallArgumentEnhanced(std::vector<ParamData> const & params,size_t paramIndex,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams) const2390 std::string VulkanHppGenerator::generateCallArgumentEnhanced( std::vector<ParamData> const & params,
2391                                                               size_t                         paramIndex,
2392                                                               bool                           nonConstPointerAsNullptr,
2393                                                               std::set<size_t> const &       singularParams,
2394                                                               std::set<size_t> const &       templatedParams ) const
2395 {
2396   std::string       argument;
2397   ParamData const & param = params[paramIndex];
2398   if ( param.type.isConstPointer() || ( specialPointerTypes.find( param.type.type ) != specialPointerTypes.end() ) )
2399   {
2400     // parameter is a const-pointer or one of the special pointer types that are considered to be const-pointers
2401     argument = generateCallArgumentEnhancedConstPointer( param, paramIndex, singularParams, templatedParams );
2402   }
2403   else if ( param.type.isNonConstPointer() && ( specialPointerTypes.find( param.type.type ) == specialPointerTypes.end() ) )
2404   {
2405     // parameter is a non-const pointer and none of the special pointer types, that are considered const-pointers
2406     argument = generateCallArgumentEnhancedNonConstPointer( param, paramIndex, nonConstPointerAsNullptr, singularParams );
2407   }
2408   else
2409   {
2410     argument = generateCallArgumentEnhancedValue( params, paramIndex, singularParams );
2411   }
2412   assert( !argument.empty() );
2413   return argument;
2414 }
2415 
generateCallArgumentEnhancedConstPointer(ParamData const & param,size_t paramIndex,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams) const2416 std::string VulkanHppGenerator::generateCallArgumentEnhancedConstPointer( ParamData const &        param,
2417                                                                           size_t                   paramIndex,
2418                                                                           std::set<size_t> const & singularParams,
2419                                                                           std::set<size_t> const & templatedParams ) const
2420 {
2421   std::string argument;
2422   std::string name = startLowerCase( stripPrefix( param.name, "p" ) );
2423   if ( isHandleType( param.type.type ) && param.type.isValue() )
2424   {
2425     assert( !param.optional );
2426     // if at all, this is the first argument, and it's the implicitly provided member handle
2427     assert( paramIndex == 0 );
2428     assert( param.arraySizes.empty() && param.len.empty() );
2429     argument = "m_" + startLowerCase( stripPrefix( param.type.type, "Vk" ) );
2430   }
2431   else if ( param.len.empty() )
2432   {
2433     // this const-pointer parameter has no length, that is it's a const-pointer to a single value
2434     if ( param.type.type == "void" )
2435     {
2436       argument = ( templatedParams.find( paramIndex ) == templatedParams.end() )
2437                  ? param.name
2438                  : "reinterpret_cast<" + param.type.compose( "VULKAN_HPP_NAMESPACE" ) + ">( &" + name + " )";
2439     }
2440     else if ( param.optional )
2441     {
2442       argument = "static_cast<" + param.type.compose( "VULKAN_HPP_NAMESPACE" ) + ">( " + name + " )";
2443     }
2444     else
2445     {
2446       argument = "&" + name;
2447     }
2448     if ( param.type.type.starts_with( "Vk" ) )
2449     {
2450       argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2451     }
2452   }
2453   else if ( param.len == "null-terminated" )
2454   {
2455     // this const-pointer parameter is "null-terminated", that is it's a string
2456     assert( ( param.type.type == "char" ) && param.arraySizes.empty() );
2457     if ( param.optional )
2458     {
2459       argument = name + " ? " + name + "->c_str() : nullptr";
2460     }
2461     else
2462     {
2463       argument = name + ".c_str()";
2464     }
2465   }
2466   else
2467   {
2468     // this const-pointer parameter has some explicit length
2469     if ( singularParams.find( paramIndex ) != singularParams.end() )
2470     {
2471       assert( !param.optional );
2472       argument = "&" + stripPluralS( name, m_tags );
2473     }
2474     else
2475     {
2476       // this const-parameter is represented by some array, where data() also works with no data (optional)
2477       argument = name + ".data()";
2478     }
2479     if ( param.type.type.starts_with( "Vk" ) || ( param.type.type == "void" ) )
2480     {
2481       argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2482     }
2483   }
2484   return argument;
2485 }
2486 
generateCallArgumentEnhancedNonConstPointer(ParamData const & param,size_t paramIndex,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams) const2487 std::string VulkanHppGenerator::generateCallArgumentEnhancedNonConstPointer( ParamData const &        param,
2488                                                                              size_t                   paramIndex,
2489                                                                              bool                     nonConstPointerAsNullptr,
2490                                                                              std::set<size_t> const & singularParams ) const
2491 {
2492   std::string argument;
2493   std::string name = startLowerCase( stripPrefix( param.name, "p" ) );
2494   if ( param.len.empty() )
2495   {
2496     assert( param.arraySizes.empty() );
2497     if ( param.type.type.starts_with( "Vk" ) )
2498     {
2499       argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( &" + name + " )";
2500     }
2501     else
2502     {
2503       assert( !param.optional );
2504       argument = "&" + name;
2505     }
2506   }
2507   else
2508   {
2509     // the non-const pointer has a len -> it will be represented by some array
2510     assert( param.arraySizes.empty() );
2511     if ( nonConstPointerAsNullptr )
2512     {
2513       argument = "nullptr";
2514     }
2515     else
2516     {
2517       if ( singularParams.find( paramIndex ) != singularParams.end() )
2518       {
2519         argument = "&" + stripPluralS( name, m_tags );
2520       }
2521       else
2522       {
2523         // get the data of the array, which also covers no data -> no need to look at param.optional
2524         argument = name + ".data()";
2525       }
2526       if ( param.type.type.starts_with( "Vk" ) || ( param.type.type == "void" ) )
2527       {
2528         argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2529       }
2530     }
2531   }
2532   return argument;
2533 }
2534 
generateCallArgumentEnhancedValue(std::vector<ParamData> const & params,size_t paramIndex,std::set<size_t> const & singularParams) const2535 std::string VulkanHppGenerator::generateCallArgumentEnhancedValue( std::vector<ParamData> const & params,
2536                                                                    size_t                         paramIndex,
2537                                                                    std::set<size_t> const &       singularParams ) const
2538 {
2539   std::string       argument;
2540   ParamData const & param = params[paramIndex];
2541   assert( param.len.empty() );
2542   if ( param.type.type.starts_with( "Vk" ) )
2543   {
2544     if ( param.arraySizes.empty() )
2545     {
2546       auto pointerIt = std::find_if( params.begin(), params.end(), [&param]( ParamData const & pd ) { return pd.len == param.name; } );
2547       if ( pointerIt != params.end() )
2548       {
2549         assert( !param.optional );
2550         argument = startLowerCase( stripPrefix( pointerIt->name, "p" ) ) + ".size()";
2551         if ( pointerIt->type.type == "void" )
2552         {
2553           argument += " * sizeof( " + stripPrefix( pointerIt->name, "p" ) + "Type )";
2554         }
2555       }
2556       else
2557       {
2558         argument = "static_cast<" + param.type.compose( "" ) + ">( " + param.name + " )";
2559       }
2560       assert( std::find_if( params.begin(), params.end(), [&param]( ParamData const & pd ) { return pd.stride == param.name; } ) == params.end() );
2561     }
2562     else
2563     {
2564       assert( !param.optional );
2565       assert( param.arraySizes.size() == 1 );
2566       assert( param.type.prefix == "const" );
2567       argument = "reinterpret_cast<" + param.type.compose( "" ) + " *>( " + param.name + " )";
2568     }
2569   }
2570   else
2571   {
2572     auto pointerIt = std::find_if( params.begin(), params.end(), [&param]( ParamData const & pd ) { return pd.len == param.name; } );
2573     if ( pointerIt != params.end() )
2574     {
2575       // this parameter is the len of some other -> replace it with that parameter's size
2576       assert( param.arraySizes.empty() );
2577       assert( ( param.type.type == "size_t" ) || ( param.type.type == "uint32_t" ) );
2578       if ( singularParams.find( paramIndex ) == singularParams.end() )
2579       {
2580         argument = startLowerCase( stripPrefix( pointerIt->name, "p" ) ) + ".size()";
2581         if ( pointerIt->type.type == "void" )
2582         {
2583           argument += " * sizeof( " + stripPrefix( pointerIt->name, "p" ) + "Type )";
2584         }
2585       }
2586       else
2587       {
2588         if ( pointerIt->type.type == "void" )
2589         {
2590           argument = "sizeof( " + stripPrefix( pointerIt->name, "p" ) + "Type )";
2591         }
2592         else
2593         {
2594           argument = "1";
2595         }
2596       }
2597     }
2598     else
2599     {
2600       assert( !param.optional );
2601       assert( param.arraySizes.size() <= 1 );
2602       pointerIt = std::find_if( params.begin(), params.end(), [&param]( ParamData const & pd ) { return pd.stride == param.name; } );
2603       if ( pointerIt != params.end() )
2604       {
2605         // this parameter is the stride of some other -> replace it with that parameter's stride
2606         assert( param.arraySizes.empty() );
2607         assert( param.type.type == "uint32_t" );
2608         argument = startLowerCase( stripPrefix( pointerIt->name, "p" ) ) + ".stride()";
2609       }
2610       else
2611       {
2612         argument = param.name;
2613       }
2614     }
2615   }
2616   return argument;
2617 }
2618 
generateCallSequence(std::string const & name,CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,size_t initialSkipCount,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool raii) const2619 std::string VulkanHppGenerator::generateCallSequence( std::string const &                       name,
2620                                                       CommandData const &                       commandData,
2621                                                       std::vector<size_t> const &               returnParams,
2622                                                       std::map<size_t, VectorParamData> const & vectorParams,
2623                                                       size_t                                    initialSkipCount,
2624                                                       std::set<size_t> const &                  singularParams,
2625                                                       std::set<size_t> const &                  templatedParams,
2626                                                       CommandFlavourFlags                       flavourFlags,
2627                                                       bool                                      raii ) const
2628 {
2629   std::string dispatcher = raii ? "getDispatcher()->" : "d.";
2630   // if at least one returnParam is a size value of a vector param (and no singular params), we need two calls
2631   if ( singularParams.empty() &&
2632        ( std::find_if( returnParams.begin(),
2633                        returnParams.end(),
2634                        [&vectorParams]( size_t rp )
2635                        {
2636                          return ( std::find_if( vectorParams.begin(), vectorParams.end(), [rp]( auto const & vp ) { return vp.second.lenParam == rp; } ) !=
2637                                   vectorParams.end() );
2638                        } ) != returnParams.end() ) )
2639   {
2640     auto vectorParamIt = vectorParams.find( returnParams[1] );
2641     assert( ( vectorParamIt != vectorParams.end() ) && ( vectorParamIt->second.lenParam == returnParams[0] ) );
2642 
2643     std::string firstCallArguments  = generateCallArgumentsEnhanced( commandData, initialSkipCount, true, {}, templatedParams, raii );
2644     std::string secondCallArguments = generateCallArgumentsEnhanced( commandData, initialSkipCount, false, {}, templatedParams, raii );
2645     std::string vectorName          = startLowerCase( stripPrefix( commandData.params[vectorParamIt->first].name, "p" ) );
2646     std::string vectorSize          = startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) );
2647 
2648     if ( flavourFlags & CommandFlavourFlagBits::chained )
2649     {
2650       assert( vectorParams.size() == 1 );
2651       // chained data needs some more handling!!
2652       std::string vectorElementType = stripPostfix( commandData.params[vectorParamIt->first].type.compose( "VULKAN_HPP_NAMESPACE" ), " *" );
2653 
2654       if ( commandData.returnType == "VkResult" )
2655       {
2656         const std::string callSequenceTemplate = R"(VkResult result;
2657     do
2658     {
2659       result = ${dispatcher}${vkCommand}( ${firstCallArguments} );
2660       if ( ( result == VK_SUCCESS ) && ${counterName} )
2661       {
2662         structureChains.resize( ${counterName} );
2663         ${vectorName}.resize( ${counterName} );
2664         for ( ${counterType} i = 0; i < ${counterName}; i++ )
2665         {
2666           ${vectorName}[i].pNext = structureChains[i].template get<${vectorElementType}>().pNext;
2667         }
2668         result = ${dispatcher}${vkCommand}( ${secondCallArguments} );
2669       }
2670     } while ( result == VK_INCOMPLETE );)";
2671 
2672         return replaceWithMap( callSequenceTemplate,
2673                                { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
2674                                  { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
2675                                  { "dispatcher", dispatcher },
2676                                  { "firstCallArguments", firstCallArguments },
2677                                  { "secondCallArguments", secondCallArguments },
2678                                  { "vectorElementType", vectorElementType },
2679                                  { "vectorName", vectorName },
2680                                  { "vkCommand", name } } );
2681       }
2682       else
2683       {
2684         const std::string callSequenceTemplate =
2685           R"(${dispatcher}${vkCommand}( ${firstCallArguments} );
2686     structureChains.resize( ${counterName} );
2687     ${vectorName}.resize( ${counterName} );
2688     for ( ${counterType} i = 0; i < ${counterName}; i++ )
2689     {
2690       ${vectorName}[i].pNext = structureChains[i].template get<${vectorElementType}>().pNext;
2691     }
2692     ${dispatcher}${vkCommand}( ${secondCallArguments} );)";
2693 
2694         return replaceWithMap( callSequenceTemplate,
2695                                { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
2696                                  { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
2697                                  { "dispatcher", dispatcher },
2698                                  { "firstCallArguments", firstCallArguments },
2699                                  { "secondCallArguments", secondCallArguments },
2700                                  { "vectorElementType", vectorElementType },
2701                                  { "vectorName", vectorName },
2702                                  { "vkCommand", name } } );
2703       }
2704     }
2705     else if ( commandData.returnType == "VkResult" )
2706     {
2707       assert( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[0] == "VK_SUCCESS" ) &&
2708               ( commandData.successCodes[1] == "VK_INCOMPLETE" ) );
2709 
2710       std::string resizes;
2711       for ( auto const & vp : vectorParams )
2712       {
2713         assert( ( std::find( returnParams.begin(), returnParams.end(), vp.first ) != returnParams.end() ) &&
2714                 ( std::find( returnParams.begin(), returnParams.end(), vp.second.lenParam ) != returnParams.end() ) );
2715         resizes += startLowerCase( stripPrefix( commandData.params[vp.first].name, "p" ) ) + ".resize( " +
2716                    startLowerCase( stripPrefix( commandData.params[vp.second.lenParam].name, "p" ) ) + " );\n";
2717       }
2718       resizes.pop_back();
2719 
2720       std::string const callSequenceTemplate = R"(VkResult result;
2721     do
2722     {
2723       result = ${dispatcher}${vkCommand}( ${firstCallArguments} );
2724       if ( ( result == VK_SUCCESS ) && ${counterName} )
2725       {
2726         ${resizes}
2727         result = ${dispatcher}${vkCommand}( ${secondCallArguments} );
2728       }
2729     } while ( result == VK_INCOMPLETE );)";
2730 
2731       return replaceWithMap( callSequenceTemplate,
2732                              { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
2733                                { "dispatcher", dispatcher },
2734                                { "firstCallArguments", firstCallArguments },
2735                                { "secondCallArguments", secondCallArguments },
2736                                { "resizes", resizes },
2737                                { "vkCommand", name } } );
2738     }
2739     else
2740     {
2741       // no need to enumerate here, just two calls
2742       assert( commandData.returnType == "void" );
2743       std::string const callSequenceTemplate = R"(${dispatcher}${vkCommand}( ${firstCallArguments} );
2744     ${vectorName}.resize( ${vectorSize} );
2745     ${dispatcher}${vkCommand}( ${secondCallArguments} );)";
2746 
2747       return replaceWithMap( callSequenceTemplate,
2748                              { { "dispatcher", dispatcher },
2749                                { "firstCallArguments", firstCallArguments },
2750                                { "secondCallArguments", secondCallArguments },
2751                                { "vectorName", vectorName },
2752                                { "vectorSize", vectorSize },
2753                                { "vkCommand", name } } );
2754     }
2755   }
2756   else
2757   {
2758     std::string const callSequenceTemplate = R"(${resultAssignment}${dispatcher}${vkCommand}( ${callArguments} );)";
2759 
2760     std::string callArguments    = generateCallArgumentsEnhanced( commandData, initialSkipCount, false, singularParams, templatedParams, raii );
2761     std::string resultAssignment = generateResultAssignment( commandData );
2762 
2763     return replaceWithMap(
2764       callSequenceTemplate,
2765       { { "callArguments", callArguments }, { "dispatcher", dispatcher }, { "resultAssignment", resultAssignment }, { "vkCommand", name } } );
2766   }
2767 }
2768 
generateCommand(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const2769 std::string VulkanHppGenerator::generateCommand( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
2770 {
2771   if ( commandData.returnType == "VkResult" )
2772   {
2773     assert( !commandData.successCodes.empty() );
2774     if ( commandData.successCodes.size() == 1 )
2775     {
2776       if ( commandData.errorCodes.empty() )
2777       {
2778         return generateCommandResultSingleSuccessNoErrors( name, commandData, initialSkipCount, definition );
2779       }
2780       else
2781       {
2782         return generateCommandResultSingleSuccessWithErrors( name, commandData, initialSkipCount, definition );
2783       }
2784     }
2785     else
2786     {
2787       if ( commandData.errorCodes.empty() )
2788       {
2789         return generateCommandResultMultiSuccessNoErrors( name, commandData, initialSkipCount, definition );
2790       }
2791       else
2792       {
2793         return generateCommandResultMultiSuccessWithErrors( name, commandData, initialSkipCount, definition );
2794       }
2795     }
2796   }
2797   else if ( commandData.returnType == "void" )
2798   {
2799     std::vector<size_t> returnParams = determineReturnParams( commandData.params );
2800     switch ( returnParams.size() )
2801     {
2802       case 0: return generateCommandVoid0Return( name, commandData, initialSkipCount, definition );
2803       case 1: return generateCommandVoid1Return( name, commandData, initialSkipCount, definition, returnParams[0] );
2804       case 2: return generateCommandVoid2Return( name, commandData, initialSkipCount, definition, returnParams );
2805     }
2806   }
2807   else
2808   {
2809     return generateCommandValue( name, commandData, initialSkipCount, definition );
2810   }
2811 
2812   throw std::runtime_error( "Never encountered a function like <" + name + "> !" );
2813 }
2814 
generateCommandDefinitions() const2815 std::string VulkanHppGenerator::generateCommandDefinitions() const
2816 {
2817   const std::string commandDefinitionsTemplate = R"(
2818   //===========================
2819   //=== COMMAND Definitions ===
2820   //===========================
2821 
2822 ${commandDefinitions}
2823 )";
2824 
2825   std::string           commandDefinitions;
2826   std::set<std::string> listedCommands;  // some commands are listed with more than one extension!
2827   for ( auto const & feature : m_features )
2828   {
2829     commandDefinitions += generateCommandDefinitions( feature.second.requireData, listedCommands, feature.first );
2830   }
2831   for ( auto const & extIt : m_extensionsByNumber )
2832   {
2833     commandDefinitions += generateCommandDefinitions( extIt.second->second.requireData, listedCommands, extIt.second->first );
2834   }
2835 
2836   return replaceWithMap( commandDefinitionsTemplate, { { "commandDefinitions", commandDefinitions } } );
2837 }
2838 
generateCommandDefinitions(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title) const2839 std::string VulkanHppGenerator::generateCommandDefinitions( std::vector<RequireData> const & requireData,
2840                                                             std::set<std::string> &          listedCommands,
2841                                                             std::string const &              title ) const
2842 {
2843   std::string str;
2844   for ( auto const & require : requireData )
2845   {
2846     for ( auto const & command : require.commands )
2847     {
2848       if ( listedCommands.insert( command ).second )
2849       {
2850         auto commandIt = m_commands.find( command );
2851         assert( commandIt != m_commands.end() );
2852         str += generateCommandDefinitions( command, commandIt->second.handle );
2853       }
2854     }
2855   }
2856   return addTitleAndProtection( title, str );
2857 }
2858 
generateCommandDefinitions(std::string const & command,std::string const & handle) const2859 std::string VulkanHppGenerator::generateCommandDefinitions( std::string const & command, std::string const & handle ) const
2860 {
2861   auto commandIt = m_commands.find( command );
2862   assert( commandIt != m_commands.end() );
2863 
2864   std::string str = "\n" + generateCommand( commandIt->first, commandIt->second, handle.empty() ? 0 : 1, true );
2865 
2866   // special handling for destroy functions, filter out alias functions
2867   std::string commandName = generateCommandName( commandIt->first, commandIt->second.params, 1, m_tags );
2868   if ( commandIt->second.alias.empty() &&
2869        ( ( ( commandIt->first.substr( 2, 7 ) == "Destroy" ) && ( commandName != "destroy" ) ) || ( commandIt->first.substr( 2, 4 ) == "Free" ) ||
2870          ( commandIt->first == "vkReleasePerformanceConfigurationINTEL" ) ) )
2871   {
2872     CommandData commandData = commandIt->second;
2873     assert( ( 1 < commandData.params.size() ) && ( commandData.params[0].type.type == handle ) );
2874     commandData.params[1].optional = false;  // make sure, the object to destroy/free/release is not optional in the shortened version!
2875 
2876     std::string destroyCommandString = generateCommand( commandIt->first, commandData, handle.empty() ? 0 : 1, true );
2877     std::string shortenedName;
2878     if ( commandIt->first.substr( 2, 7 ) == "Destroy" )
2879     {
2880       shortenedName = "destroy";
2881     }
2882     else if ( commandIt->first.substr( 2, 4 ) == "Free" )
2883     {
2884       shortenedName = "free";
2885     }
2886     else
2887     {
2888       assert( commandIt->first == "vkReleasePerformanceConfigurationINTEL" );
2889       shortenedName = "release";
2890     }
2891     size_t pos = destroyCommandString.find( commandName );
2892     while ( pos != std::string::npos )
2893     {
2894       destroyCommandString.replace( pos, commandName.length(), shortenedName );
2895       pos = destroyCommandString.find( commandName, pos );
2896     }
2897 
2898     // special handling for "free", to prevent interfering with MSVC debug free!
2899     if ( shortenedName == "free" )
2900     {
2901       std::string toEncloseString = stripPrefix( handle, "Vk" ) + "::free";
2902       std::string enclosedString  = "( " + toEncloseString + " )";
2903       pos                         = destroyCommandString.find( toEncloseString );
2904       while ( pos != std::string::npos )
2905       {
2906         destroyCommandString.replace( pos, toEncloseString.length(), enclosedString );
2907         pos = destroyCommandString.find( toEncloseString, pos + enclosedString.length() );
2908       }
2909     }
2910 
2911     // we need to remove the default argument for the first argument, to prevent ambiguities!
2912     assert( 1 < commandIt->second.params.size() );
2913     pos = destroyCommandString.find( commandIt->second.params[1].name );  // skip the standard version of the function
2914     assert( pos != std::string::npos );
2915     pos = destroyCommandString.find( commandIt->second.params[1].name,
2916                                      pos + 1 );  // get the argument to destroy in the advanced version
2917     assert( pos != std::string::npos );
2918     pos = destroyCommandString.find( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT", pos );
2919     if ( pos != std::string::npos )
2920     {
2921       destroyCommandString.erase( pos, strlen( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT" ) );
2922     }
2923     str += "\n" + destroyCommandString;
2924   }
2925   return str;
2926 }
2927 
generateCommandEnhanced(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,CommandFlavourFlags flavourFlags) const2928 std::string VulkanHppGenerator::generateCommandEnhanced( std::string const &                       name,
2929                                                          CommandData const &                       commandData,
2930                                                          size_t                                    initialSkipCount,
2931                                                          bool                                      definition,
2932                                                          std::map<size_t, VectorParamData> const & vectorParams,
2933                                                          std::vector<size_t> const &               returnParams,
2934                                                          CommandFlavourFlags                       flavourFlags ) const
2935 {
2936   bool singular = flavourFlags & CommandFlavourFlagBits::singular;
2937 
2938   assert( vectorParams.empty() || ( vectorParams.begin()->second.lenParam != INVALID_INDEX ) );
2939   assert( !singular || !returnParams.empty() );  // if singular is true, then there is at least one returnParam !
2940 
2941   std::set<size_t> skippedParams = determineSkippedParams( commandData.params, initialSkipCount, vectorParams, returnParams, singular );
2942   // special handling for vkGetMemoryHostPointerPropertiesEXT: here, we really need to stick with the const void * parameter !
2943   std::set<size_t> templatedParams = ( name == "vkGetMemoryHostPointerPropertiesEXT" ) ? std::set<size_t>() : determineVoidPointerParams( commandData.params );
2944   std::set<size_t> singularParams  = singular ? determineSingularParams( returnParams[0], vectorParams ) : std::set<size_t>();
2945   std::pair<bool, std::map<size_t, std::vector<size_t>>> vectorSizeCheck =
2946     needsVectorSizeCheck( commandData.params, vectorParams, returnParams, singularParams );
2947   bool enumerating = determineEnumeration( vectorParams, returnParams );
2948 
2949   std::vector<std::string> dataTypes = determineDataTypes( commandData.params, vectorParams, returnParams, templatedParams );
2950   std::string              dataType  = combineDataTypes( vectorParams, returnParams, enumerating, dataTypes, flavourFlags, false );
2951 
2952   std::string argumentTemplates = generateArgumentTemplates( commandData.params, returnParams, vectorParams, templatedParams, flavourFlags, false );
2953   auto [allocatorTemplates, uniqueHandleAllocatorTemplates] = generateAllocatorTemplates( returnParams, dataTypes, vectorParams, flavourFlags, definition );
2954   std::string typenameCheck                                 = generateTypenameCheck( returnParams, vectorParams, definition, dataTypes, flavourFlags );
2955   std::string nodiscard      = generateNoDiscard( !returnParams.empty(), 1 < commandData.successCodes.size(), 1 < commandData.errorCodes.size() );
2956   std::string returnType     = generateReturnType( commandData, returnParams, vectorParams, flavourFlags, false, dataType );
2957   std::string className      = initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "";
2958   std::string classSeparator = commandData.handle.empty() ? "" : "::";
2959   std::string commandName    = generateCommandName( name, commandData.params, initialSkipCount, m_tags, flavourFlags );
2960   std::string argumentList   = generateArgumentListEnhanced(
2961     commandData.params, returnParams, vectorParams, skippedParams, singularParams, templatedParams, definition, flavourFlags, true );
2962   std::string constString    = commandData.handle.empty() ? "" : " const";
2963   std::string noexceptString = generateNoExcept( commandData.errorCodes, returnParams, vectorParams, flavourFlags, vectorSizeCheck.first, false );
2964 
2965   if ( definition )
2966   {
2967     std::string vectorSizeCheckString =
2968       vectorSizeCheck.first ? generateVectorSizeCheck( name, commandData, initialSkipCount, vectorSizeCheck.second, skippedParams, false ) : "";
2969     std::string returnVariable   = generateReturnVariable( commandData, returnParams, vectorParams, flavourFlags );
2970     std::string dataDeclarations = generateDataDeclarations(
2971       commandData, returnParams, vectorParams, templatedParams, flavourFlags, false, dataTypes, dataType, returnType, returnVariable );
2972     std::string dataPreparation =
2973       generateDataPreparation( commandData, initialSkipCount, returnParams, vectorParams, templatedParams, flavourFlags, enumerating );
2974     std::string dataSizeChecks = generateDataSizeChecks( commandData, returnParams, dataTypes, vectorParams, templatedParams, singular );
2975     std::string callSequence =
2976       generateCallSequence( name, commandData, returnParams, vectorParams, initialSkipCount, singularParams, templatedParams, flavourFlags, false );
2977     std::string resultCheck     = generateResultCheck( commandData, className, classSeparator, commandName, enumerating );
2978     std::string returnStatement = generateReturnStatement( name,
2979                                                            commandData,
2980                                                            returnVariable,
2981                                                            returnType,
2982                                                            dataType,
2983                                                            initialSkipCount,
2984                                                            returnParams.empty() ? INVALID_INDEX : returnParams[0],
2985                                                            flavourFlags,
2986                                                            enumerating,
2987                                                            false );
2988 
2989     std::string const functionTemplate =
2990       R"(  template <${argumentTemplates}${allocatorTemplates}typename Dispatch${uniqueHandleAllocatorTemplates}${typenameCheck}>
2991   ${nodiscard}VULKAN_HPP_INLINE ${returnType} ${className}${classSeparator}${commandName}( ${argumentList} )${const}${noexcept}
2992   {
2993     VULKAN_HPP_ASSERT( d.getVkHeaderVersion() == VK_HEADER_VERSION );
2994 ${vectorSizeCheck}
2995     ${dataSizeChecks}
2996     ${dataDeclarations}
2997     ${callSequence}
2998     ${resultCheck}
2999     ${dataPreparation}
3000     ${returnStatement}
3001   })";
3002 
3003     return replaceWithMap( functionTemplate,
3004                            { { "allocatorTemplates", allocatorTemplates },
3005                              { "argumentList", argumentList },
3006                              { "argumentTemplates", argumentTemplates },
3007                              { "callSequence", callSequence },
3008                              { "className", className },
3009                              { "classSeparator", classSeparator },
3010                              { "commandName", commandName },
3011                              { "const", constString },
3012                              { "dataDeclarations", dataDeclarations },
3013                              { "dataPreparation", dataPreparation },
3014                              { "dataSizeChecks", dataSizeChecks },
3015                              { "nodiscard", nodiscard },
3016                              { "noexcept", noexceptString },
3017                              { "resultCheck", resultCheck },
3018                              { "returnStatement", returnStatement },
3019                              { "returnType", returnType },
3020                              { "typenameCheck", typenameCheck },
3021                              { "uniqueHandleAllocatorTemplates", uniqueHandleAllocatorTemplates },
3022                              { "vectorSizeCheck", vectorSizeCheckString } } );
3023   }
3024   else
3025   {
3026     std::string const functionTemplate =
3027       R"(    template <${argumentTemplates}${allocatorTemplates}typename Dispatch = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE${uniqueHandleAllocatorTemplates}${typenameCheck}>
3028     ${nodiscard}${returnType} ${commandName}( ${argumentList} )${const}${noexcept};)";
3029 
3030     return replaceWithMap( functionTemplate,
3031                            { { "allocatorTemplates", allocatorTemplates },
3032                              { "argumentList", argumentList },
3033                              { "argumentTemplates", argumentTemplates },
3034                              { "commandName", commandName },
3035                              { "const", commandData.handle.empty() ? "" : " const" },
3036                              { "nodiscard", nodiscard },
3037                              { "noexcept", noexceptString },
3038                              { "returnType", returnType },
3039                              { "typenameCheck", typenameCheck },
3040                              { "uniqueHandleAllocatorTemplates", uniqueHandleAllocatorTemplates } } );
3041   }
3042 }
3043 
generateCommandName(std::string const & vulkanCommandName,std::vector<ParamData> const & params,size_t initialSkipCount,std::set<std::string> const & tags,CommandFlavourFlags flavourFlags) const3044 std::string VulkanHppGenerator::generateCommandName( std::string const &            vulkanCommandName,
3045                                                      std::vector<ParamData> const & params,
3046                                                      size_t                         initialSkipCount,
3047                                                      std::set<std::string> const &  tags,
3048                                                      CommandFlavourFlags            flavourFlags ) const
3049 {
3050   std::string commandName( startLowerCase( stripPrefix( vulkanCommandName, "vk" ) ) );
3051   for ( size_t i = initialSkipCount - 1; i < initialSkipCount; --i )  // count down to zero, then wrap around and stop
3052   {
3053     std::string const & argumentType = params[i].type.type;
3054     std::string         searchName   = stripPrefix( argumentType, "Vk" );
3055     std::string         argumentTag  = findTag( tags, argumentType );
3056     if ( !argumentTag.empty() )
3057     {
3058       searchName = stripPostfix( searchName, argumentTag );
3059     }
3060     size_t pos = commandName.find( searchName );
3061     if ( pos == std::string::npos )
3062     {
3063       searchName = startLowerCase( searchName );
3064       pos        = commandName.find( searchName );
3065     }
3066     if ( pos != std::string::npos )
3067     {
3068       size_t len = searchName.length();
3069       if ( commandName.find( searchName + "s" ) == pos )
3070       {
3071         // filter out any plural of the searchName as well!
3072         ++len;
3073       }
3074       commandName.erase( pos, len );
3075     }
3076     else if ( ( searchName == "commandBuffer" ) && commandName.starts_with( "cmd" ) )
3077     {
3078       commandName.erase( 0, 3 );
3079       pos = 0;
3080     }
3081     if ( pos == 0 )
3082     {
3083       commandName = startLowerCase( commandName );
3084     }
3085     std::string commandTag = findTag( tags, commandName );
3086     if ( !argumentTag.empty() && ( argumentTag == commandTag ) )
3087     {
3088       commandName = stripPostfix( commandName, argumentTag );
3089     }
3090   }
3091   if ( flavourFlags & CommandFlavourFlagBits::singular )
3092   {
3093     commandName = stripPluralS( commandName, m_tags );
3094   }
3095   if ( flavourFlags & CommandFlavourFlagBits::unique )
3096   {
3097     commandName += "Unique";
3098   }
3099   return commandName;
3100 }
3101 
generateCommandResultMultiSuccessNoErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3102 std::string VulkanHppGenerator::generateCommandResultMultiSuccessNoErrors( std::string const & name,
3103                                                                            CommandData const & commandData,
3104                                                                            size_t              initialSkipCount,
3105                                                                            bool                definition ) const
3106 {
3107   std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3108   switch ( returnParams.size() )
3109   {
3110     case 0: return generateCommandResultMultiSuccessNoErrors0Return( name, commandData, initialSkipCount, definition ); break;
3111     case 2: return generateCommandResultMultiSuccessNoErrors2Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3112   }
3113   return "";
3114 }
3115 
generateCommandResultMultiSuccessNoErrors0Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3116 std::string VulkanHppGenerator::generateCommandResultMultiSuccessNoErrors0Return( std::string const & name,
3117                                                                                   CommandData const & commandData,
3118                                                                                   size_t              initialSkipCount,
3119                                                                                   bool                definition ) const
3120 {
3121   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3122   if ( vectorParams.empty() )
3123   {
3124     std::vector<size_t> constPointerParams = determineConstPointerParams( commandData.params );
3125     if ( constPointerParams.empty() )
3126     {
3127       return generateCommandSet( generateCommandStandard( name, commandData, initialSkipCount, definition ),
3128                                  generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, {} ) );
3129     }
3130   }
3131   return "";
3132 }
3133 
generateCommandResultMultiSuccessNoErrors2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3134 std::string VulkanHppGenerator::generateCommandResultMultiSuccessNoErrors2Return(
3135   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3136 {
3137   if ( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[0] == "VK_SUCCESS" ) && ( commandData.successCodes[1] == "VK_INCOMPLETE" ) )
3138   {
3139     if ( ( commandData.params[returnParams[0]].type.type == "size_t" ) || ( commandData.params[returnParams[0]].type.type == "uint32_t" ) )
3140     {
3141       if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3142            !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3143       {
3144         std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3145         if ( vectorParams.size() == 1 )
3146         {
3147           if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3148           {
3149             if ( returnParams[1] == vectorParams.begin()->first )
3150             {
3151               return generateCommandSet(
3152                 definition,
3153                 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3154                 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3155                   generateCommandEnhanced(
3156                     name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
3157             }
3158           }
3159         }
3160       }
3161     }
3162   }
3163   return "";
3164 }
3165 
generateCommandResultMultiSuccessWithErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3166 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors( std::string const & name,
3167                                                                              CommandData const & commandData,
3168                                                                              size_t              initialSkipCount,
3169                                                                              bool                definition ) const
3170 {
3171   std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3172   switch ( returnParams.size() )
3173   {
3174     case 0: return generateCommandResultWithErrors0Return( name, commandData, initialSkipCount, definition ); break;
3175     case 1: return generateCommandResultMultiSuccessWithErrors1Return( name, commandData, initialSkipCount, definition, returnParams[0] ); break;
3176     case 2: return generateCommandResultMultiSuccessWithErrors2Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3177     case 3: return generateCommandResultMultiSuccessWithErrors3Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3178   }
3179   return "";
3180 }
3181 
generateCommandResultMultiSuccessWithErrors1Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3182 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors1Return(
3183   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3184 {
3185   if ( commandData.params[returnParam].type.type == "void" )
3186   {
3187     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3188     if ( vectorParams.size() == 1 )
3189     {
3190       if ( returnParam == vectorParams.begin()->first )
3191       {
3192         if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3193         {
3194           return generateCommandSet(
3195             definition,
3196             generateCommandStandard( name, commandData, initialSkipCount, definition ),
3197             { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3198               generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3199         }
3200       }
3201     }
3202   }
3203   else if ( isHandleType( commandData.params[returnParam].type.type ) )
3204   {
3205     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3206     if ( vectorParams.size() == 2 )
3207     {
3208       if ( returnParam == std::next( vectorParams.begin() )->first )
3209       {
3210         if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3211         {
3212           if ( commandData.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
3213           {
3214             if ( isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) )
3215             {
3216               return generateCommandSet(
3217                 definition,
3218                 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3219                 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3220                   generateCommandEnhanced(
3221                     name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ),
3222                   generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) },
3223                 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::unique ),
3224                   generateCommandEnhanced( name,
3225                                            commandData,
3226                                            initialSkipCount,
3227                                            definition,
3228                                            vectorParams,
3229                                            { returnParam },
3230                                            CommandFlavourFlagBits::unique | CommandFlavourFlagBits::withAllocator ),
3231                   generateCommandEnhanced( name,
3232                                            commandData,
3233                                            initialSkipCount,
3234                                            definition,
3235                                            vectorParams,
3236                                            { returnParam },
3237                                            CommandFlavourFlagBits::unique | CommandFlavourFlagBits::singular ) } );
3238             }
3239           }
3240         }
3241       }
3242     }
3243   }
3244   else if ( isStructureChainAnchor( commandData.params[returnParam].type.type ) )
3245   {
3246     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3247     if ( vectorParams.empty() )
3248     {
3249       return generateCommandSet(
3250         definition,
3251         generateCommandStandard( name, commandData, initialSkipCount, definition ),
3252         { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3253           generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::chained ) } );
3254     }
3255   }
3256   else
3257   {
3258     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3259     if ( vectorParams.empty() )
3260     {
3261       return generateCommandSet( definition,
3262                                  generateCommandStandard( name, commandData, initialSkipCount, definition ),
3263                                  { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3264     }
3265   }
3266   return "";
3267 }
3268 
generateCommandResultMultiSuccessWithErrors2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3269 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors2Return(
3270   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3271 {
3272   if ( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[0] == "VK_SUCCESS" ) && ( commandData.successCodes[1] == "VK_INCOMPLETE" ) )
3273   {
3274     if ( ( commandData.params[returnParams[0]].type.type == "size_t" ) || ( commandData.params[returnParams[0]].type.type == "uint32_t" ) )
3275     {
3276       if ( isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3277       {
3278         std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3279         if ( vectorParams.size() == 1 )
3280         {
3281           if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3282           {
3283             if ( returnParams[1] == vectorParams.begin()->first )
3284             {
3285               return generateCommandSet(
3286                 definition,
3287                 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3288                 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3289                   generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ),
3290                   generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::chained ),
3291                   generateCommandEnhanced( name,
3292                                            commandData,
3293                                            initialSkipCount,
3294                                            definition,
3295                                            vectorParams,
3296                                            returnParams,
3297                                            CommandFlavourFlagBits::chained | CommandFlavourFlagBits::withAllocator ) } );
3298             }
3299           }
3300         }
3301       }
3302       else
3303       {
3304         std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3305         if ( vectorParams.size() == 1 )
3306         {
3307           if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3308           {
3309             if ( returnParams[1] == vectorParams.begin()->first )
3310             {
3311               return generateCommandSet(
3312                 definition,
3313                 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3314                 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3315                   generateCommandEnhanced(
3316                     name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
3317             }
3318           }
3319         }
3320       }
3321     }
3322     else if ( ( commandData.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[0]].type.type ) &&
3323               !isStructureChainAnchor( commandData.params[returnParams[0]].type.type ) )
3324     {
3325       if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3326            !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3327       {
3328         std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3329         if ( vectorParams.empty() )
3330         {
3331           return generateCommandSet( definition,
3332                                      generateCommandStandard( name, commandData, initialSkipCount, definition ),
3333                                      { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ) } );
3334         }
3335       }
3336     }
3337   }
3338   return "";
3339 }
3340 
generateCommandResultMultiSuccessWithErrors3Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3341 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors3Return(
3342   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3343 {
3344   if ( commandData.params[returnParams[0]].type.type == "uint32_t" )
3345   {
3346     if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3347          !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3348     {
3349       if ( ( commandData.params[returnParams[2]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[2]].type.type ) &&
3350            !isStructureChainAnchor( commandData.params[returnParams[2]].type.type ) )
3351       {
3352         std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3353         if ( vectorParams.size() == 2 )
3354         {
3355           if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3356           {
3357             if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3358             {
3359               if ( returnParams[1] == vectorParams.begin()->first )
3360               {
3361                 if ( returnParams[2] == std::next( vectorParams.begin() )->first )
3362                 {
3363                   return generateCommandSet(
3364                     definition,
3365                     generateCommandStandard( name, commandData, initialSkipCount, definition ),
3366                     { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3367                       generateCommandEnhanced(
3368                         name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
3369                 }
3370               }
3371             }
3372           }
3373         }
3374       }
3375     }
3376   }
3377   return "";
3378 }
3379 
generateCommandResultSingleSuccessNoErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3380 std::string VulkanHppGenerator::generateCommandResultSingleSuccessNoErrors( std::string const & name,
3381                                                                             CommandData const & commandData,
3382                                                                             size_t              initialSkipCount,
3383                                                                             bool                definition ) const
3384 {
3385   std::vector<size_t>               returnParams = determineReturnParams( commandData.params );
3386   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3387   switch ( returnParams.size() )
3388   {
3389     case 0:
3390       switch ( vectorParams.size() )
3391       {
3392         case 0:
3393           {
3394             std::vector<size_t> constPointerParams = determineConstPointerParams( commandData.params );
3395             switch ( constPointerParams.size() )
3396             {
3397               case 0:
3398                 return generateCommandSet( generateCommandStandard( name, commandData, initialSkipCount, definition ),
3399                                            generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, {} ) );
3400               case 1:
3401                 return generateCommandSet( definition,
3402                                            generateCommandStandard( name, commandData, initialSkipCount, definition ),
3403                                            { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, {} ) } );
3404             }
3405           }
3406           break;
3407         case 1:
3408           if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3409           {
3410             if ( isHandleType( commandData.params[vectorParams.begin()->first].type.type ) )
3411             {
3412               return generateCommandSet( definition,
3413                                          generateCommandStandard( name, commandData, initialSkipCount, definition ),
3414                                          { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) } );
3415             }
3416           }
3417           break;
3418       }
3419       break;
3420     case 1:
3421       if ( vectorParams.empty() )
3422       {
3423         if ( ( commandData.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[0]].type.type ) &&
3424              !isStructureChainAnchor( commandData.params[returnParams[0]].type.type ) )
3425         {
3426           return generateCommandSet( definition,
3427                                      generateCommandStandard( name, commandData, initialSkipCount, definition ),
3428                                      { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ) } );
3429         }
3430       }
3431       break;
3432   }
3433   return "";
3434 }
3435 
generateCommandResultSingleSuccessWithErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3436 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors( std::string const & name,
3437                                                                               CommandData const & commandData,
3438                                                                               size_t              initialSkipCount,
3439                                                                               bool                definition ) const
3440 {
3441   std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3442   switch ( returnParams.size() )
3443   {
3444     case 0: return generateCommandResultWithErrors0Return( name, commandData, initialSkipCount, definition ); break;
3445     case 1: return generateCommandResultSingleSuccessWithErrors1Return( name, commandData, initialSkipCount, definition, returnParams[0] ); break;
3446     case 2: return generateCommandResultSingleSuccessWithErrors2Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3447   }
3448   return "";
3449 }
3450 
generateCommandResultSingleSuccessWithErrors1Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3451 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1Return(
3452   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3453 {
3454   if ( commandData.params[returnParam].type.type == "void" )
3455   {
3456     return generateCommandResultSingleSuccessWithErrors1ReturnVoid( name, commandData, initialSkipCount, definition, returnParam );
3457   }
3458   else if ( isHandleType( commandData.params[returnParam].type.type ) )
3459   {
3460     return generateCommandResultSingleSuccessWithErrors1ReturnHandle( name, commandData, initialSkipCount, definition, returnParam );
3461   }
3462   else if ( isStructureChainAnchor( commandData.params[returnParam].type.type ) )
3463   {
3464     return generateCommandResultSingleSuccessWithErrors1ReturnChain( name, commandData, initialSkipCount, definition, returnParam );
3465   }
3466   else
3467   {
3468     return generateCommandResultSingleSuccessWithErrors1ReturnValue( name, commandData, initialSkipCount, definition, returnParam );
3469   }
3470 }
3471 
generateCommandResultSingleSuccessWithErrors1ReturnChain(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3472 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnChain(
3473   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3474 {
3475   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3476   if ( vectorParams.empty() )
3477   {
3478     return generateCommandSet(
3479       definition,
3480       generateCommandStandard( name, commandData, initialSkipCount, definition ),
3481       { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3482         generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::chained ) } );
3483   }
3484   return "";
3485 }
3486 
generateCommandResultSingleSuccessWithErrors1ReturnHandle(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3487 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnHandle(
3488   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3489 {
3490   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3491   switch ( vectorParams.size() )
3492   {
3493     case 0:
3494       return generateCommandSet(
3495         definition,
3496         generateCommandStandard( name, commandData, initialSkipCount, definition ),
3497         { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) },
3498         { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::unique ) } );
3499       break;
3500     case 1:
3501       return generateCommandResultSingleSuccessWithErrors1ReturnHandle1Vector(
3502         name, commandData, initialSkipCount, definition, returnParam, *vectorParams.begin() );
3503       break;
3504     case 2:
3505       return generateCommandResultSingleSuccessWithErrors1ReturnHandle2Vector( name, commandData, initialSkipCount, definition, returnParam, vectorParams );
3506       break;
3507   }
3508   return "";
3509 }
3510 
3511 std::string
generateCommandResultSingleSuccessWithErrors1ReturnHandle1Vector(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam,std::pair<size_t,VectorParamData> const & vectorParamIndex) const3512   VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnHandle1Vector( std::string const &                        name,
3513                                                                                         CommandData const &                        commandData,
3514                                                                                         size_t                                     initialSkipCount,
3515                                                                                         bool                                       definition,
3516                                                                                         size_t                                     returnParam,
3517                                                                                         std::pair<size_t, VectorParamData> const & vectorParamIndex ) const
3518 {
3519   if ( returnParam == vectorParamIndex.first )
3520   {
3521     if ( isLenByStructMember( commandData.params[vectorParamIndex.first].len, commandData.params[vectorParamIndex.second.lenParam] ) )
3522     {
3523       return generateCommandSet(
3524         definition,
3525         generateCommandStandard( name, commandData, initialSkipCount, definition ),
3526         { generateCommandEnhanced( name, commandData, initialSkipCount, definition, { vectorParamIndex }, { returnParam } ),
3527           generateCommandEnhanced(
3528             name, commandData, initialSkipCount, definition, { vectorParamIndex }, { returnParam }, CommandFlavourFlagBits::withAllocator ) },
3529         { generateCommandEnhanced( name, commandData, initialSkipCount, definition, { vectorParamIndex }, { returnParam }, CommandFlavourFlagBits::unique ),
3530           generateCommandEnhanced( name,
3531                                    commandData,
3532                                    initialSkipCount,
3533                                    definition,
3534                                    { vectorParamIndex },
3535                                    { returnParam },
3536                                    CommandFlavourFlagBits::unique | CommandFlavourFlagBits::withAllocator ) } );
3537     }
3538   }
3539   return "";
3540 }
3541 
generateCommandResultSingleSuccessWithErrors1ReturnHandle2Vector(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const3542 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnHandle2Vector( std::string const &                       name,
3543                                                                                                   CommandData const &                       commandData,
3544                                                                                                   size_t                                    initialSkipCount,
3545                                                                                                   bool                                      definition,
3546                                                                                                   size_t                                    returnParam,
3547                                                                                                   std::map<size_t, VectorParamData> const & vectorParams ) const
3548 {
3549   if ( returnParam == std::next( vectorParams.begin() )->first )
3550   {
3551     if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3552     {
3553       if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3554       {
3555         if ( ( commandData.params[vectorParams.begin()->first].type.type != "void" ) &&
3556              !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) )
3557         {
3558           return generateCommandSet(
3559             definition,
3560             generateCommandStandard( name, commandData, initialSkipCount, definition ),
3561             { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3562               generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ),
3563               generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) },
3564             { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::unique ),
3565               generateCommandEnhanced( name,
3566                                        commandData,
3567                                        initialSkipCount,
3568                                        definition,
3569                                        vectorParams,
3570                                        { returnParam },
3571                                        CommandFlavourFlagBits::unique | CommandFlavourFlagBits::withAllocator ),
3572               generateCommandEnhanced( name,
3573                                        commandData,
3574                                        initialSkipCount,
3575                                        definition,
3576                                        vectorParams,
3577                                        { returnParam },
3578                                        CommandFlavourFlagBits::singular | CommandFlavourFlagBits::unique ) } );
3579         }
3580       }
3581     }
3582   }
3583   return "";
3584 }
3585 
generateCommandResultSingleSuccessWithErrors1ReturnValue(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3586 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnValue(
3587   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3588 {
3589   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3590   switch ( vectorParams.size() )
3591   {
3592     case 0:
3593       return generateCommandSet( definition,
3594                                  generateCommandStandard( name, commandData, initialSkipCount, definition ),
3595                                  { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3596     case 2:
3597       return generateCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( name, commandData, initialSkipCount, definition, returnParam, vectorParams );
3598       break;
3599   }
3600   return "";
3601 }
3602 
generateCommandResultSingleSuccessWithErrors1ReturnValue2Vectors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const3603 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( std::string const &                       name,
3604                                                                                                   CommandData const &                       commandData,
3605                                                                                                   size_t                                    initialSkipCount,
3606                                                                                                   bool                                      definition,
3607                                                                                                   size_t                                    returnParam,
3608                                                                                                   std::map<size_t, VectorParamData> const & vectorParams ) const
3609 {
3610   if ( returnParam == std::next( vectorParams.begin() )->first )
3611   {
3612     if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3613     {
3614       if ( commandData.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
3615       {
3616         if ( ( commandData.params[vectorParams.begin()->first].type.type != "void" ) &&
3617              !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) &&
3618              !isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) )
3619         {
3620           return generateCommandSet(
3621             definition,
3622             generateCommandStandard( name, commandData, initialSkipCount, definition ),
3623             { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3624               generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ),
3625               generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3626         }
3627       }
3628     }
3629   }
3630   return "";
3631 }
3632 
generateCommandResultSingleSuccessWithErrors1ReturnVoid(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3633 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnVoid(
3634   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3635 {
3636   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3637   switch ( vectorParams.size() )
3638   {
3639     case 0:
3640       return generateCommandSet( definition,
3641                                  generateCommandStandard( name, commandData, initialSkipCount, definition ),
3642                                  { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3643       break;
3644     case 1:
3645       if ( returnParam == vectorParams.begin()->first )
3646       {
3647         if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3648         {
3649           return generateCommandSet(
3650             definition,
3651             generateCommandStandard( name, commandData, initialSkipCount, definition ),
3652             { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3653               generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3654         }
3655       }
3656       break;
3657     case 2:
3658       if ( returnParam == std::next( vectorParams.begin() )->first )
3659       {
3660         if ( vectorParams.begin()->second.lenParam != std::next( vectorParams.begin() )->second.lenParam )
3661         {
3662           if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3663           {
3664             if ( isHandleType( commandData.params[vectorParams.begin()->first].type.type ) )
3665             {
3666               if ( commandData.params[std::next( vectorParams.begin() )->second.lenParam].type.isValue() )
3667               {
3668                 return generateCommandSet(
3669                   definition,
3670                   generateCommandStandard( name, commandData, initialSkipCount, definition ),
3671                   { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3672                     generateCommandEnhanced(
3673                       name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3674               }
3675             }
3676           }
3677         }
3678       }
3679       break;
3680   }
3681   return "";
3682 }
3683 
generateCommandResultSingleSuccessWithErrors2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3684 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors2Return(
3685   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3686 {
3687   if ( ( commandData.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[0]].type.type ) &&
3688        !isStructureChainAnchor( commandData.params[returnParams[0]].type.type ) )
3689   {
3690     if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3691          !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3692     {
3693       std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3694       if ( vectorParams.size() == 2 )
3695       {
3696         if ( returnParams[0] == std::next( vectorParams.begin() )->first )
3697         {
3698           if ( vectorParams.find( returnParams[1] ) == vectorParams.end() )
3699           {
3700             assert( ( returnParams[1] != vectorParams.begin()->second.lenParam ) && ( returnParams[1] != std::next( vectorParams.begin() )->second.lenParam ) );
3701             if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3702             {
3703               if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3704               {
3705                 if ( ( commandData.params[vectorParams.begin()->first].type.type != "void" ) &&
3706                      !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) &&
3707                      !isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) )
3708                 {
3709                   return generateCommandSet(
3710                     definition,
3711                     generateCommandStandard( name, commandData, initialSkipCount, definition ),
3712                     { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3713                       generateCommandEnhanced(
3714                         name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ),
3715                       generateCommandEnhanced(
3716                         name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::singular ) } );
3717                 }
3718               }
3719             }
3720           }
3721         }
3722       }
3723     }
3724   }
3725   return "";
3726 }
3727 
generateCommandResultWithErrors0Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3728 std::string VulkanHppGenerator::generateCommandResultWithErrors0Return( std::string const & name,
3729                                                                         CommandData const & commandData,
3730                                                                         size_t              initialSkipCount,
3731                                                                         bool                definition ) const
3732 {
3733   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3734   if ( vectorParams.empty() && determineConstPointerParams( commandData.params ).empty() )
3735   {
3736     return generateCommandSet( generateCommandStandard( name, commandData, initialSkipCount, definition ),
3737                                generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) );
3738   }
3739   else if ( allVectorSizesSupported( commandData.params, vectorParams ) )
3740   {
3741     return generateCommandSet( definition,
3742                                generateCommandStandard( name, commandData, initialSkipCount, definition ),
3743                                { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) } );
3744   }
3745   return "";
3746 }
3747 
generateCommandSet(bool definition,std::string const & standard,std::vector<std::string> const & enhanced,std::vector<std::string> const & unique) const3748 std::string VulkanHppGenerator::generateCommandSet( bool                             definition,
3749                                                     std::string const &              standard,
3750                                                     std::vector<std::string> const & enhanced,
3751                                                     std::vector<std::string> const & unique ) const
3752 {
3753   assert( unique.empty() || ( enhanced.size() == unique.size() ) );
3754 
3755   std::string commandSet = "\n" + standard;
3756   if ( !enhanced.empty() )
3757   {
3758     std::string separator = definition ? "\n" : "";
3759     commandSet += separator + "\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n";
3760     bool firstEnhanced = true;
3761     for ( auto const & e : enhanced )
3762     {
3763       if ( !firstEnhanced )
3764       {
3765         commandSet += separator + "\n";
3766       }
3767       firstEnhanced = false;
3768       commandSet += e;
3769     }
3770     if ( !unique.empty() )
3771     {
3772       commandSet += separator + "\n#  ifndef VULKAN_HPP_NO_SMART_HANDLE\n";
3773       bool firstUnique = true;
3774       for ( auto const & u : unique )
3775       {
3776         if ( !firstUnique )
3777         {
3778           commandSet += separator + "\n";
3779         }
3780         firstUnique = false;
3781         commandSet += u;
3782       }
3783       commandSet += "\n#  endif /* VULKAN_HPP_NO_SMART_HANDLE */";
3784     }
3785     commandSet += "\n#endif /* VULKAN_HPP_DISABLE_ENHANCED_MODE */";
3786   }
3787   commandSet += "\n";
3788   return commandSet;
3789 }
3790 
generateCommandSet(std::string const & standard,std::string const & enhanced) const3791 std::string VulkanHppGenerator::generateCommandSet( std::string const & standard, std::string const & enhanced ) const
3792 {
3793   const std::string commandTemplate = R"(
3794 #ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE
3795 ${commandStandard}
3796 #else
3797 ${commandEnhanced}
3798 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
3799 )";
3800 
3801   return replaceWithMap( commandTemplate, std::map<std::string, std::string>( { { "commandEnhanced", enhanced }, { "commandStandard", standard } } ) );
3802 }
3803 
3804 std::string
generateCommandStandard(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3805   VulkanHppGenerator::generateCommandStandard( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
3806 {
3807   std::set<size_t> skippedParams = determineSkippedParams( commandData.params, initialSkipCount, {}, {}, false );
3808 
3809   std::string argumentList = generateArgumentListStandard( commandData.params, skippedParams );
3810   std::string commandName  = generateCommandName( name, commandData.params, initialSkipCount, m_tags );
3811   std::string nodiscard    = ( 1 < commandData.successCodes.size() + commandData.errorCodes.size() ) ? "VULKAN_HPP_NODISCARD " : "";
3812   std::string returnType   = stripPrefix( commandData.returnType, "Vk" );
3813 
3814   if ( definition )
3815   {
3816     std::string functionBody = "d." + name + "( " + generateCallArgumentsStandard( commandData.handle, commandData.params ) + " )";
3817     if ( commandData.returnType.starts_with( "Vk" ) )
3818     {
3819       functionBody = "return static_cast<" + returnType + ">( " + functionBody + " )";
3820     }
3821     else if ( commandData.returnType != "void" )
3822     {
3823       functionBody = "return " + functionBody;
3824     }
3825 
3826     std::string const functionTemplate =
3827       R"(  template <typename Dispatch>
3828   ${nodiscard}VULKAN_HPP_INLINE ${returnType} ${className}${classSeparator}${commandName}( ${argumentList} )${const} VULKAN_HPP_NOEXCEPT
3829   {
3830     VULKAN_HPP_ASSERT( d.getVkHeaderVersion() == VK_HEADER_VERSION );
3831     ${functionBody};
3832   })";
3833 
3834     return replaceWithMap( functionTemplate,
3835                            { { "argumentList", argumentList },
3836                              { "className", initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "" },
3837                              { "classSeparator", commandData.handle.empty() ? "" : "::" },
3838                              { "commandName", commandName },
3839                              { "const", commandData.handle.empty() ? "" : " const" },
3840                              { "functionBody", functionBody },
3841                              { "nodiscard", nodiscard },
3842                              { "returnType", returnType } } );
3843   }
3844   else
3845   {
3846     std::string const functionTemplate =
3847       R"(    template <typename Dispatch = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
3848     ${nodiscard}${returnType} ${commandName}( ${argumentList} VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )${const} VULKAN_HPP_NOEXCEPT;)";
3849 
3850     return replaceWithMap( functionTemplate,
3851                            { { "argumentList", argumentList },
3852                              { "commandName", commandName },
3853                              { "const", commandData.handle.empty() ? "" : " const" },
3854                              { "nodiscard", nodiscard },
3855                              { "returnType", returnType } } );
3856   }
3857 }
3858 
3859 std::string
generateCommandValue(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3860   VulkanHppGenerator::generateCommandValue( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
3861 {
3862   std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3863   if ( returnParams.empty() )
3864   {
3865     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3866     if ( vectorParams.empty() && determineConstPointerParams( commandData.params ).empty() )
3867     {
3868       return generateCommandSet( definition, generateCommandStandard( name, commandData, initialSkipCount, definition ) );
3869     }
3870     else if ( vectorParams.size() <= 1 )
3871     {
3872       return generateCommandSet( definition,
3873                                  generateCommandStandard( name, commandData, initialSkipCount, definition ),
3874                                  { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ) } );
3875     }
3876   }
3877   return "";
3878 }
3879 
3880 std::string
generateCommandVoid0Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3881   VulkanHppGenerator::generateCommandVoid0Return( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
3882 {
3883   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3884   if ( vectorParams.empty() && determineConstPointerParams( commandData.params ).empty() )
3885   {
3886     return generateCommandSet( definition, generateCommandStandard( name, commandData, initialSkipCount, definition ) );
3887   }
3888   else if ( allVectorSizesSupported( commandData.params, vectorParams ) )
3889   {
3890     // All the vectorParams have a counter by value, of type "uint32_t", "VkDeviceSize", or "VkSampleCountFlagBits" (!)
3891     return generateCommandSet( definition,
3892                                generateCommandStandard( name, commandData, initialSkipCount, definition ),
3893                                { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) } );
3894   }
3895   return "";
3896 }
3897 
generateCommandVoid1Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3898 std::string VulkanHppGenerator::generateCommandVoid1Return(
3899   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3900 {
3901   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3902   if ( commandData.params[returnParam].type.postfix == "**" )
3903   {
3904     // get a pointer to something
3905     if ( commandData.params[returnParam].type.type == "void" )
3906     {
3907       if ( vectorParams.empty() )
3908       {
3909         return generateCommandSet( definition,
3910                                    generateCommandStandard( name, commandData, initialSkipCount, definition ),
3911                                    { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ) } );
3912       }
3913     }
3914   }
3915   else if ( isHandleType( commandData.params[returnParam].type.type ) )
3916   {
3917     if ( vectorParams.empty() )
3918     {
3919       return generateCommandSet( definition,
3920                                  generateCommandStandard( name, commandData, initialSkipCount, definition ),
3921                                  { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ) } );
3922     }
3923   }
3924   else if ( isStructureChainAnchor( commandData.params[returnParam].type.type ) )
3925   {
3926     if ( vectorParams.empty() )
3927     {
3928       return generateCommandSet(
3929         definition,
3930         generateCommandStandard( name, commandData, initialSkipCount, definition ),
3931         { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ),
3932           generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam }, CommandFlavourFlagBits::chained ) } );
3933     }
3934   }
3935   else if ( commandData.params[returnParam].type.type == "void" )
3936   {
3937     switch ( vectorParams.size() )
3938     {
3939       case 0:
3940         return generateCommandSet( definition,
3941                                    generateCommandStandard( name, commandData, initialSkipCount, definition ),
3942                                    { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3943       case 1:
3944         if ( returnParam == vectorParams.begin()->first )
3945         {
3946           if ( name == stripPluralS( name, m_tags ) )
3947           {
3948             return generateCommandSet(
3949               definition,
3950               generateCommandStandard( name, commandData, initialSkipCount, definition ),
3951               { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3952           }
3953         }
3954         break;
3955     }
3956   }
3957   else
3958   {
3959     switch ( vectorParams.size() )
3960     {
3961       case 0:
3962         return generateCommandSet( definition,
3963                                    generateCommandStandard( name, commandData, initialSkipCount, definition ),
3964                                    { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ) } );
3965         break;
3966       case 1:
3967         if ( returnParam == vectorParams.begin()->first )
3968         {
3969           // you get a vector of stuff, with the size being one of the parameters
3970           return generateCommandSet(
3971             definition,
3972             generateCommandStandard( name, commandData, initialSkipCount, definition ),
3973             { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3974               generateCommandEnhanced(
3975                 name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ) } );
3976         }
3977         else
3978         {
3979           if ( !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) &&
3980                !isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) &&
3981                ( commandData.params[vectorParams.begin()->first].type.type != "void" ) )
3982           {
3983             if ( isLenByStructMember( commandData.params[vectorParams.begin()->first].len, commandData.params[vectorParams.begin()->second.lenParam] ) )
3984             {
3985               return generateCommandSet( definition,
3986                                          generateCommandStandard( name, commandData, initialSkipCount, definition ),
3987                                          { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3988             }
3989           }
3990         }
3991         break;
3992     }
3993   }
3994   return "";
3995 }
3996 
generateCommandVoid2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3997 std::string VulkanHppGenerator::generateCommandVoid2Return(
3998   std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3999 {
4000   if ( commandData.params[returnParams[0]].type.type == "uint32_t" )
4001   {
4002     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
4003     if ( vectorParams.size() == 1 )
4004     {
4005       if ( returnParams[0] == vectorParams.begin()->second.lenParam )
4006       {
4007         if ( returnParams[1] == vectorParams.begin()->first )
4008         {
4009           if ( isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
4010           {
4011             return generateCommandSet(
4012               definition,
4013               generateCommandStandard( name, commandData, initialSkipCount, definition ),
4014               { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
4015                 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ),
4016                 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::chained ),
4017                 generateCommandEnhanced( name,
4018                                          commandData,
4019                                          initialSkipCount,
4020                                          definition,
4021                                          vectorParams,
4022                                          returnParams,
4023                                          CommandFlavourFlagBits::chained | CommandFlavourFlagBits::withAllocator ) } );
4024           }
4025           else if ( !isHandleType( commandData.params[returnParams[1]].type.type ) )
4026           {
4027             return generateCommandSet(
4028               definition,
4029               generateCommandStandard( name, commandData, initialSkipCount, definition ),
4030               { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
4031                 generateCommandEnhanced(
4032                   name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
4033           }
4034         }
4035       }
4036     }
4037   }
4038   return "";
4039 }
4040 
generateConstexprString(std::string const & structName) const4041 std::string VulkanHppGenerator::generateConstexprString( std::string const & structName ) const
4042 {
4043   // structs with a VkBaseInStructure and VkBaseOutStructure can't be a constexpr!
4044   bool isConstExpression = ( structName != "VkBaseInStructure" ) && ( structName != "VkBaseOutStructure" );
4045   return isConstExpression ? ( std::string( "VULKAN_HPP_CONSTEXPR" ) + ( ( containsUnion( structName ) || containsArray( structName ) ) ? "_14 " : " " ) ) : "";
4046 }
4047 
generateDataDeclarations(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool raii,std::vector<std::string> const & dataTypes,std::string const & dataType,std::string const & returnType,std::string const & returnVariable) const4048 std::string VulkanHppGenerator::generateDataDeclarations( CommandData const &                       commandData,
4049                                                           std::vector<size_t> const &               returnParams,
4050                                                           std::map<size_t, VectorParamData> const & vectorParams,
4051                                                           std::set<size_t> const &                  templatedParams,
4052                                                           CommandFlavourFlags                       flavourFlags,
4053                                                           bool                                      raii,
4054                                                           std::vector<std::string> const &          dataTypes,
4055                                                           std::string const &                       dataType,
4056                                                           std::string const &                       returnType,
4057                                                           std::string const &                       returnVariable ) const
4058 {
4059   assert( dataTypes.size() == returnParams.size() );
4060 
4061   switch ( returnParams.size() )
4062   {
4063     case 0: return "";  // no returnParams -> no data declarations
4064     case 1:
4065       return generateDataDeclarations1Return(
4066         commandData, returnParams, vectorParams, templatedParams, flavourFlags, dataTypes, dataType, returnType, returnVariable );
4067     case 2:
4068       assert( !( flavourFlags & CommandFlavourFlagBits::unique ) );
4069       return generateDataDeclarations2Returns( commandData, returnParams, vectorParams, flavourFlags, raii, dataTypes, dataType, returnVariable );
4070     case 3:
4071       assert( ( vectorParams.size() == 2 ) && ( returnParams[0] == vectorParams.begin()->second.lenParam ) &&
4072               ( returnParams[1] == vectorParams.begin()->first ) && ( returnParams[2] == std::next( vectorParams.begin() )->first ) &&
4073               ( returnParams[0] == std::next( vectorParams.begin() )->second.lenParam ) && templatedParams.empty() &&
4074               !( flavourFlags & ( CommandFlavourFlagBits::chained | CommandFlavourFlagBits::singular | CommandFlavourFlagBits::unique ) ) );
4075       return generateDataDeclarations3Returns( commandData, returnParams, flavourFlags, raii, dataTypes );
4076     default: assert( false ); return "";
4077   }
4078 }
4079 
generateDataDeclarations1Return(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,std::vector<std::string> const & dataTypes,std::string const & dataType,std::string const & returnType,std::string const & returnVariable) const4080 std::string VulkanHppGenerator::generateDataDeclarations1Return( CommandData const &                       commandData,
4081                                                                  std::vector<size_t> const &               returnParams,
4082                                                                  std::map<size_t, VectorParamData> const & vectorParams,
4083                                                                  std::set<size_t> const &                  templatedParams,
4084                                                                  CommandFlavourFlags                       flavourFlags,
4085                                                                  std::vector<std::string> const &          dataTypes,
4086                                                                  std::string const &                       dataType,
4087                                                                  std::string const &                       returnType,
4088                                                                  std::string const &                       returnVariable ) const
4089 {
4090   auto vectorParamIt = vectorParams.find( returnParams[0] );
4091   if ( !( flavourFlags & CommandFlavourFlagBits::chained ) )
4092   {
4093     if ( ( vectorParamIt == vectorParams.end() ) || ( flavourFlags & CommandFlavourFlagBits::singular ) )
4094     {
4095       std::string const dataDeclarationsTemplate = R"(${returnType} ${returnVariable};)";
4096 
4097       return replaceWithMap( dataDeclarationsTemplate, { { "returnType", dataType }, { "returnVariable", returnVariable } } );
4098     }
4099     else
4100     {
4101       std::string allocator       = stripPrefix( dataTypes[0], "VULKAN_HPP_NAMESPACE::" ) + "Allocator";
4102       std::string vectorAllocator = ( ( flavourFlags & CommandFlavourFlagBits::withAllocator ) && !( flavourFlags & CommandFlavourFlagBits::unique ) )
4103                                     ? ( ", " + startLowerCase( allocator ) )
4104                                     : "";
4105       std::string vectorSize      = getVectorSize( commandData.params, vectorParams, returnParams[0], dataTypes[0], templatedParams );
4106 
4107       std::string const dataDeclarationsTemplate = R"(${dataType} ${returnVariable}( ${vectorSize}${vectorAllocator} );)";
4108 
4109       return replaceWithMap(
4110         dataDeclarationsTemplate,
4111         { { "dataType", dataType }, { "returnVariable", returnVariable }, { "vectorAllocator", vectorAllocator }, { "vectorSize", vectorSize } } );
4112     }
4113   }
4114   else
4115   {
4116     assert( ( vectorParamIt == vectorParams.end() ) || ( flavourFlags & CommandFlavourFlagBits::singular ) );
4117 
4118     std::string dataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4119 
4120     std::string const dataDeclarationsTemplate = R"(${returnType} ${returnVariable};
4121     ${dataType} & ${dataVariable} = ${returnVariable}.template get<${dataType}>();)";
4122 
4123     return replaceWithMap( dataDeclarationsTemplate,
4124                            { { "dataType", dataTypes[0] },
4125                              { "dataVariable", dataVariable },
4126                              { "returnType", ( commandData.returnType == "void" ) ? returnType : "StructureChain<X, Y, Z...>" },
4127                              { "returnVariable", returnVariable } } );
4128   }
4129 }
4130 
generateDataDeclarations2Returns(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool raii,std::vector<std::string> const & dataTypes,std::string const & dataType,std::string const & returnVariable) const4131 std::string VulkanHppGenerator::generateDataDeclarations2Returns( CommandData const &                       commandData,
4132                                                                   std::vector<size_t> const &               returnParams,
4133                                                                   std::map<size_t, VectorParamData> const & vectorParams,
4134                                                                   CommandFlavourFlags                       flavourFlags,
4135                                                                   bool                                      raii,
4136                                                                   std::vector<std::string> const &          dataTypes,
4137                                                                   std::string const &                       dataType,
4138                                                                   std::string const &                       returnVariable ) const
4139 {
4140   bool chained       = flavourFlags & CommandFlavourFlagBits::chained;
4141   bool singular      = flavourFlags & CommandFlavourFlagBits::singular;
4142   bool withAllocator = flavourFlags & CommandFlavourFlagBits::withAllocator;
4143 
4144   switch ( vectorParams.size() )
4145   {
4146     case 0:
4147       assert( !singular && !chained );
4148       {
4149         std::string firstDataVariable  = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4150         std::string secondDataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4151 
4152         std::string const dataDeclarationTemplate = R"(std::pair<${firstDataType},${secondDataType}> data;
4153     ${firstDataType} & ${firstDataVariable} = data.first;
4154     ${secondDataType} & ${secondDataVariable} = data.second;)";
4155 
4156         return replaceWithMap( dataDeclarationTemplate,
4157                                { { "firstDataType", dataTypes[0] },
4158                                  { "firstDataVariable", firstDataVariable },
4159                                  { "secondDataType", dataTypes[1] },
4160                                  { "secondDataVariable", secondDataVariable } } );
4161       }
4162       break;
4163     case 1:
4164       assert( ( returnParams[0] == vectorParams.begin()->second.lenParam ) && ( returnParams[1] == vectorParams.begin()->first ) && !singular );
4165       {
4166         std::string counterVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4167         if ( !chained )
4168         {
4169           std::string vectorAllocator = withAllocator ? ( "( " + startLowerCase( stripPrefix( dataTypes[1], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator )" ) : "";
4170 
4171           std::string const dataDeclarationTemplate = R"(${returnType} ${returnVariable}${vectorAllocator};
4172     ${counterType} ${counterVariable};)";
4173 
4174           return replaceWithMap( dataDeclarationTemplate,
4175                                  { { "counterType", dataTypes[0] },
4176                                    { "counterVariable", counterVariable },
4177                                    { "returnType", dataType },
4178                                    { "returnVariable", returnVariable },
4179                                    { "vectorAllocator", vectorAllocator } } );
4180         }
4181         else
4182         {
4183           std::string structureChainAllocator   = raii ? "" : ", StructureChainAllocator";
4184           std::string structureChainInitializer = withAllocator ? ( "( structureChainAllocator )" ) : "";
4185           std::string vectorVariable            = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4186 
4187           std::string const dataDeclarationTemplate =
4188             R"(std::vector<StructureChain${structureChainAllocator}> structureChains${structureChainInitializer};
4189     std::vector<${vectorElementType}> ${vectorVariable};
4190     ${counterType} ${counterVariable};)";
4191 
4192           return replaceWithMap( dataDeclarationTemplate,
4193                                  {
4194                                    { "counterType", dataTypes[0] },
4195                                    { "counterVariable", counterVariable },
4196                                    { "structureChainAllocator", structureChainAllocator },
4197                                    { "structureChainInitializer", structureChainInitializer },
4198                                    { "vectorElementType", dataTypes[1] },
4199                                    { "vectorVariable", vectorVariable },
4200                                  } );
4201         }
4202       }
4203       break;
4204     case 2:
4205       assert( ( returnParams[0] == std::next( vectorParams.begin() )->first ) && ( vectorParams.find( returnParams[1] ) == vectorParams.end() ) && !chained );
4206       {
4207         std::string firstDataVariable  = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4208         std::string secondDataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4209         if ( singular )
4210         {
4211           firstDataVariable = stripPluralS( firstDataVariable, m_tags );
4212 
4213           std::string const dataDeclarationTemplate = R"(std::pair<${firstDataType},${secondDataType}> data;
4214     ${firstDataType} & ${firstDataVariable} = data.first;
4215     ${secondDataType} & ${secondDataVariable} = data.second;)";
4216 
4217           return replaceWithMap( dataDeclarationTemplate,
4218                                  { { "firstDataType", dataTypes[0] },
4219                                    { "firstDataVariable", firstDataVariable },
4220                                    { "secondDataType", dataTypes[1] },
4221                                    { "secondDataVariable", secondDataVariable } } );
4222         }
4223         else
4224         {
4225           std::string allocatorType       = raii ? "" : ( startUpperCase( stripPrefix( dataTypes[0], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator" );
4226           std::string allocateInitializer = withAllocator ? ( ", " + startLowerCase( allocatorType ) ) : "";
4227           if ( !raii )
4228           {
4229             allocatorType = ", " + allocatorType;
4230           }
4231           std::string vectorSize = startLowerCase( stripPrefix( commandData.params[vectorParams.begin()->first].name, "p" ) ) + ".size()";
4232 
4233           std::string const dataDeclarationTemplate =
4234             R"(std::pair<std::vector<${firstDataType}${allocatorType}>,${secondDataType}> data( std::piecewise_construct, std::forward_as_tuple( ${vectorSize}${allocateInitializer} ), std::forward_as_tuple( 0 ) );
4235     std::vector<${firstDataType}${allocatorType}> & ${firstDataVariable} = data.first;
4236     ${secondDataType} & ${secondDataVariable} = data.second;)";
4237 
4238           return replaceWithMap( dataDeclarationTemplate,
4239                                  { { "allocateInitializer", allocateInitializer },
4240                                    { "allocatorType", allocatorType },
4241                                    { "firstDataType", dataTypes[0] },
4242                                    { "firstDataVariable", firstDataVariable },
4243                                    { "secondDataType", dataTypes[1] },
4244                                    { "secondDataVariable", secondDataVariable },
4245                                    { "vectorSize", vectorSize } } );
4246         }
4247       }
4248       break;
4249     default: assert( false ); return "";
4250   }
4251 }
4252 
generateDataDeclarations3Returns(CommandData const & commandData,std::vector<size_t> const & returnParams,CommandFlavourFlags flavourFlags,bool raii,std::vector<std::string> const & dataTypes) const4253 std::string VulkanHppGenerator::generateDataDeclarations3Returns( CommandData const &              commandData,
4254                                                                   std::vector<size_t> const &      returnParams,
4255                                                                   CommandFlavourFlags              flavourFlags,
4256                                                                   bool                             raii,
4257                                                                   std::vector<std::string> const & dataTypes ) const
4258 {
4259   std::string counterVariable      = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4260   std::string firstVectorVariable  = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4261   std::string secondVectorVariable = startLowerCase( stripPrefix( commandData.params[returnParams[2]].name, "p" ) );
4262   std::string firstVectorAllocatorType, secondVectorAllocatorType, pairConstructor;
4263   if ( !raii )
4264   {
4265     firstVectorAllocatorType  = startUpperCase( stripPrefix( dataTypes[1], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator";
4266     secondVectorAllocatorType = startUpperCase( stripPrefix( dataTypes[2], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator";
4267     pairConstructor           = ( flavourFlags & CommandFlavourFlagBits::withAllocator )
4268                                 ? ( "( std::piecewise_construct, std::forward_as_tuple( " + startLowerCase( firstVectorAllocatorType ) + " ), std::forward_as_tuple( " +
4269                           startLowerCase( secondVectorAllocatorType ) + " ) )" )
4270                                 : "";
4271     firstVectorAllocatorType  = ", " + firstVectorAllocatorType;
4272     secondVectorAllocatorType = ", " + secondVectorAllocatorType;
4273   }
4274 
4275   std::string const dataDeclarationsTemplate =
4276     R"(std::pair<std::vector<${firstVectorElementType}${firstVectorAllocatorType}>, std::vector<${secondVectorElementType}${secondVectorAllocatorType}>> data${pairConstructor};
4277     std::vector<${firstVectorElementType}${firstVectorAllocatorType}> & ${firstVectorVariable} = data.first;
4278     std::vector<${secondVectorElementType}${secondVectorAllocatorType}> & ${secondVectorVariable} = data.second;
4279     ${counterType} ${counterVariable};)";
4280 
4281   return replaceWithMap( dataDeclarationsTemplate,
4282                          { { "counterType", dataTypes[0] },
4283                            { "counterVariable", counterVariable },
4284                            { "firstVectorAllocatorType", firstVectorAllocatorType },
4285                            { "firstVectorElementType", dataTypes[1] },
4286                            { "firstVectorVariable", firstVectorVariable },
4287                            { "pairConstructor", pairConstructor },
4288                            { "secondVectorAllocatorType", secondVectorAllocatorType },
4289                            { "secondVectorElementType", dataTypes[2] },
4290                            { "secondVectorVariable", secondVectorVariable } } );
4291 }
4292 
generateDataPreparation(CommandData const & commandData,size_t initialSkipCount,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool enumerating) const4293 std::string VulkanHppGenerator::generateDataPreparation( CommandData const &                       commandData,
4294                                                          size_t                                    initialSkipCount,
4295                                                          std::vector<size_t> const &               returnParams,
4296                                                          std::map<size_t, VectorParamData> const & vectorParams,
4297                                                          std::set<size_t> const &                  templatedParams,
4298                                                          CommandFlavourFlags                       flavourFlags,
4299                                                          bool                                      enumerating ) const
4300 {
4301   bool chained  = flavourFlags & CommandFlavourFlagBits::chained;
4302   bool singular = flavourFlags & CommandFlavourFlagBits::singular;
4303   bool unique   = flavourFlags & CommandFlavourFlagBits::unique;
4304 
4305   auto vectorParamIt = ( 1 < returnParams.size() ) ? vectorParams.find( returnParams[1] ) : vectorParams.end();
4306   if ( vectorParamIt != vectorParams.end() )
4307   {
4308     assert( !unique );
4309 
4310     std::string vectorName = startLowerCase( stripPrefix( commandData.params[vectorParamIt->first].name, "p" ) );
4311 
4312     if ( chained )
4313     {
4314       assert( !singular );
4315       assert( templatedParams.empty() );
4316       assert( returnParams.size() == 2 );
4317       assert( vectorParams.find( returnParams[0] ) == vectorParams.end() );
4318       assert( ( vectorParamIt != vectorParams.end() ) && ( vectorParamIt->second.lenParam == returnParams[0] ) );
4319 
4320       std::string vectorElementType = stripPostfix( commandData.params[vectorParamIt->first].type.compose( "VULKAN_HPP_NAMESPACE" ), " *" );
4321 
4322       if ( enumerating )
4323       {
4324         std::string const dataPreparationTemplate =
4325           R"(VULKAN_HPP_ASSERT( ${counterName} <= ${vectorName}.size() );
4326       if ( ${counterName} < ${vectorName}.size() )
4327       {
4328         structureChains.resize( ${counterName} );
4329       }
4330       for ( ${counterType} i = 0; i < ${counterName}; i++ )
4331       {
4332         structureChains[i].template get<${vectorElementType}>() = ${vectorName}[i];
4333       })";
4334 
4335         return replaceWithMap( dataPreparationTemplate,
4336                                { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
4337                                  { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
4338                                  { "vectorElementType", vectorElementType },
4339                                  { "vectorName", vectorName } } );
4340       }
4341       else
4342       {
4343         std::string const dataPreparationTemplate =
4344           R"(for ( ${counterType} i = 0; i < ${counterName}; i++ )
4345     {
4346       structureChains[i].template get<${vectorElementType}>() = ${vectorName}[i];
4347     })";
4348 
4349         return replaceWithMap( dataPreparationTemplate,
4350                                { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
4351                                  { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
4352                                  { "vectorElementType", vectorElementType },
4353                                  { "vectorName", vectorName } } );
4354       }
4355     }
4356     else if ( enumerating )
4357     {
4358       assert( !singular );
4359       assert( ( vectorParams.size() != 2 ) ||
4360               ( ( vectorParams.begin()->first == returnParams[1] ) && ( vectorParams.begin()->second.lenParam == returnParams[0] ) &&
4361                 ( std::next( vectorParams.begin() )->first == returnParams[2] ) &&
4362                 ( std::next( vectorParams.begin() )->second.lenParam == returnParams[0] ) ) );
4363 
4364       std::string resizes;
4365       for ( auto const & vp : vectorParams )
4366       {
4367         assert( ( std::find( returnParams.begin(), returnParams.end(), vp.first ) != returnParams.end() ) &&
4368                 ( std::find( returnParams.begin(), returnParams.end(), vp.second.lenParam ) != returnParams.end() ) );
4369         resizes += startLowerCase( stripPrefix( commandData.params[vp.first].name, "p" ) ) + ".resize( " +
4370                    startLowerCase( stripPrefix( commandData.params[vp.second.lenParam].name, "p" ) ) + " );\n";
4371       }
4372       resizes.pop_back();
4373 
4374       std::string const dataPreparationTemplate =
4375         R"(VULKAN_HPP_ASSERT( ${counterName} <= ${vectorName}.size() );
4376     if ( ${counterName} < ${vectorName}.size() )
4377     {
4378       ${resizes}
4379     })";
4380 
4381       return replaceWithMap( dataPreparationTemplate,
4382                              { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
4383                                { "resizes", resizes },
4384                                { "vectorName", vectorName } } );
4385     }
4386   }
4387   else if ( unique && !singular && ( returnParams.size() == 1 ) && ( vectorParams.find( returnParams[0] ) != vectorParams.end() ) )
4388   {
4389     assert( !enumerating );
4390     std::string              className = initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "";
4391     std::string              deleterDefinition;
4392     std::vector<std::string> lenParts = tokenize( commandData.params[returnParams[0]].len, "->" );
4393     switch ( lenParts.size() )
4394     {
4395       case 1: deleterDefinition = "ObjectDestroy<" + className + ", Dispatch> deleter( *this, allocator, d )"; break;
4396       case 2:
4397         {
4398           auto vpiIt = vectorParams.find( returnParams[0] );
4399           assert( vpiIt != vectorParams.end() );
4400           std::string poolType, poolName;
4401           std::tie( poolType, poolName ) = getPoolTypeAndName( commandData.params[vpiIt->second.lenParam].type.type );
4402           assert( !poolType.empty() );
4403           poolType          = stripPrefix( poolType, "Vk" );
4404           poolName          = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + poolName;
4405           deleterDefinition = "PoolFree<" + className + ", " + poolType + ", Dispatch> deleter( *this, " + poolName + ", d )";
4406         }
4407         break;
4408     }
4409 
4410     std::string handleType       = stripPrefix( commandData.params[returnParams[0]].type.type, "Vk" );
4411     std::string uniqueVectorName = "unique" + stripPrefix( commandData.params[returnParams[0]].name, "p" );
4412     std::string vectorAllocator  = ( flavourFlags & CommandFlavourFlagBits::withAllocator ) ? ( "( " + startLowerCase( handleType ) + "Allocator )" ) : "";
4413     std::string vectorName       = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4414     std::string elementName      = stripPluralS( vectorName, m_tags );
4415     std::string vectorSize = getVectorSize( commandData.params, vectorParams, returnParams[0], commandData.params[returnParams[0]].type.type, templatedParams );
4416 
4417     std::string const dataPreparationTemplate =
4418       R"(std::vector<UniqueHandle<VULKAN_HPP_NAMESPACE::${handleType}, Dispatch>, ${handleType}Allocator> ${uniqueVectorName}${vectorAllocator};
4419     ${uniqueVectorName}.reserve( ${vectorSize} );
4420     ${deleterDefinition};
4421     for ( auto const & ${elementName} : ${vectorName} )
4422     {
4423       ${uniqueVectorName}.push_back( UniqueHandle<${handleType}, Dispatch>( ${elementName}, deleter ) );
4424     })";
4425 
4426     return replaceWithMap( dataPreparationTemplate,
4427                            { { "elementName", elementName },
4428                              { "deleterDefinition", deleterDefinition },
4429                              { "handleType", handleType },
4430                              { "uniqueVectorName", uniqueVectorName },
4431                              { "vectorAllocator", vectorAllocator },
4432                              { "vectorName", vectorName },
4433                              { "vectorSize", vectorSize } } );
4434   }
4435   return "";
4436 }
4437 
generateDataSizeChecks(CommandData const & commandData,std::vector<size_t> const & returnParams,std::vector<std::string> const & returnParamTypes,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,bool singular) const4438 std::string VulkanHppGenerator::generateDataSizeChecks( CommandData const &                       commandData,
4439                                                         std::vector<size_t> const &               returnParams,
4440                                                         std::vector<std::string> const &          returnParamTypes,
4441                                                         std::map<size_t, VectorParamData> const & vectorParams,
4442                                                         std::set<size_t> const &                  templatedParams,
4443                                                         bool                                      singular ) const
4444 {
4445   assert( returnParams.size() == returnParamTypes.size() );
4446   std::string dataSizeChecks;
4447   if ( !singular )
4448   {
4449     const std::string dataSizeCheckTemplate = R"(    VULKAN_HPP_ASSERT( ${dataSize} % sizeof( ${dataType} ) == 0 );)";
4450     for ( size_t i = 0; i < returnParams.size(); i++ )
4451     {
4452       auto vectorParamIt = vectorParams.find( returnParams[i] );
4453       if ( ( vectorParamIt != vectorParams.end() ) && ( templatedParams.find( returnParams[i] ) != templatedParams.end() ) &&
4454            ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) == returnParams.end() ) )
4455       {
4456         dataSizeChecks += replaceWithMap( dataSizeCheckTemplate,
4457                                           { { "dataSize", commandData.params[vectorParamIt->second.lenParam].name }, { "dataType", returnParamTypes[i] } } );
4458       }
4459     }
4460   }
4461 
4462   return dataSizeChecks;
4463 }
4464 
generateDispatchLoaderDynamic() const4465 std::string VulkanHppGenerator::generateDispatchLoaderDynamic() const
4466 {
4467   const std::string dispatchLoaderDynamicTemplate = R"(
4468   using PFN_dummy = void ( * )();
4469 
4470   class DispatchLoaderDynamic : public DispatchLoaderBase
4471   {
4472   public:
4473 ${commandMembers}
4474 
4475   public:
4476     DispatchLoaderDynamic() VULKAN_HPP_NOEXCEPT = default;
4477     DispatchLoaderDynamic( DispatchLoaderDynamic const & rhs ) VULKAN_HPP_NOEXCEPT = default;
4478 
4479     DispatchLoaderDynamic(PFN_vkGetInstanceProcAddr getInstanceProcAddr) VULKAN_HPP_NOEXCEPT
4480     {
4481       init(getInstanceProcAddr);
4482     }
4483 
4484     void init( PFN_vkGetInstanceProcAddr getInstanceProcAddr ) VULKAN_HPP_NOEXCEPT
4485     {
4486       VULKAN_HPP_ASSERT(getInstanceProcAddr);
4487 
4488       vkGetInstanceProcAddr = getInstanceProcAddr;
4489 
4490 ${initialCommandAssignments}
4491     }
4492 
4493     // This interface does not require a linked vulkan library.
4494     DispatchLoaderDynamic( VkInstance                instance,
4495                            PFN_vkGetInstanceProcAddr getInstanceProcAddr,
4496                            VkDevice                  device            = {},
4497                            PFN_vkGetDeviceProcAddr   getDeviceProcAddr = nullptr ) VULKAN_HPP_NOEXCEPT
4498     {
4499       init( instance, getInstanceProcAddr, device, getDeviceProcAddr );
4500     }
4501 
4502     // This interface does not require a linked vulkan library.
4503     void init( VkInstance                instance,
4504                PFN_vkGetInstanceProcAddr getInstanceProcAddr,
4505                VkDevice                  device              = {},
4506                PFN_vkGetDeviceProcAddr /*getDeviceProcAddr*/ = nullptr ) VULKAN_HPP_NOEXCEPT
4507     {
4508       VULKAN_HPP_ASSERT(instance && getInstanceProcAddr);
4509       vkGetInstanceProcAddr = getInstanceProcAddr;
4510       init( VULKAN_HPP_NAMESPACE::Instance(instance) );
4511       if (device) {
4512         init( VULKAN_HPP_NAMESPACE::Device(device) );
4513       }
4514     }
4515 
4516     void init( VULKAN_HPP_NAMESPACE::Instance instanceCpp ) VULKAN_HPP_NOEXCEPT
4517     {
4518       VkInstance instance = static_cast<VkInstance>(instanceCpp);
4519 
4520 ${instanceCommandAssignments}
4521     }
4522 
4523     void init( VULKAN_HPP_NAMESPACE::Device deviceCpp ) VULKAN_HPP_NOEXCEPT
4524     {
4525       VkDevice device = static_cast<VkDevice>(deviceCpp);
4526 
4527 ${deviceCommandAssignments}
4528     }
4529 
4530     template <typename DynamicLoader>
4531     void init(VULKAN_HPP_NAMESPACE::Instance const & instance, VULKAN_HPP_NAMESPACE::Device const & device, DynamicLoader const & dl) VULKAN_HPP_NOEXCEPT
4532     {
4533       PFN_vkGetInstanceProcAddr getInstanceProcAddr = dl.template getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
4534       PFN_vkGetDeviceProcAddr getDeviceProcAddr = dl.template getProcAddress<PFN_vkGetDeviceProcAddr>("vkGetDeviceProcAddr");
4535       init(static_cast<VkInstance>(instance), getInstanceProcAddr, static_cast<VkDevice>(device), device ? getDeviceProcAddr : nullptr);
4536     }
4537 
4538     template <typename DynamicLoader
4539 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
4540       = VULKAN_HPP_NAMESPACE::DynamicLoader
4541 #endif
4542     >
4543     void init(VULKAN_HPP_NAMESPACE::Instance const & instance, VULKAN_HPP_NAMESPACE::Device const & device) VULKAN_HPP_NOEXCEPT
4544     {
4545       static DynamicLoader dl;
4546       init(instance, device, dl);
4547     }
4548   };)";
4549 
4550   std::string           commandMembers, deviceCommandAssignments, initialCommandAssignments, instanceCommandAssignments;
4551   std::set<std::string> listedCommands;  // some commands are listed with more than one extension!
4552   for ( auto const & feature : m_features )
4553   {
4554     appendDispatchLoaderDynamicCommands( feature.second.requireData,
4555                                          listedCommands,
4556                                          feature.first,
4557                                          commandMembers,
4558                                          initialCommandAssignments,
4559                                          instanceCommandAssignments,
4560                                          deviceCommandAssignments );
4561   }
4562   for ( auto const & extIt : m_extensionsByNumber )
4563   {
4564     appendDispatchLoaderDynamicCommands( extIt.second->second.requireData,
4565                                          listedCommands,
4566                                          extIt.second->first,
4567                                          commandMembers,
4568                                          initialCommandAssignments,
4569                                          instanceCommandAssignments,
4570                                          deviceCommandAssignments );
4571   }
4572 
4573   return replaceWithMap( dispatchLoaderDynamicTemplate,
4574                          { { "commandMembers", commandMembers },
4575                            { "deviceCommandAssignments", deviceCommandAssignments },
4576                            { "initialCommandAssignments", initialCommandAssignments },
4577                            { "instanceCommandAssignments", instanceCommandAssignments } } );
4578 }
4579 
generateDispatchLoaderStatic() const4580 std::string VulkanHppGenerator::generateDispatchLoaderStatic() const
4581 {
4582   const std::string dispatchLoaderStaticTemplate = R"(
4583 #if !defined( VK_NO_PROTOTYPES )
4584   class DispatchLoaderStatic : public DispatchLoaderBase
4585   {
4586   public:
4587 ${commands}
4588   };
4589 #endif
4590 )";
4591 
4592   std::string           commands;
4593   std::set<std::string> listedCommands;
4594   for ( auto const & feature : m_features )
4595   {
4596     commands += generateDispatchLoaderStaticCommands( feature.second.requireData, listedCommands, feature.first );
4597   }
4598   for ( auto const & extIt : m_extensionsByNumber )
4599   {
4600     commands += generateDispatchLoaderStaticCommands( extIt.second->second.requireData, listedCommands, extIt.second->first );
4601   }
4602 
4603   return replaceWithMap( dispatchLoaderStaticTemplate, { { "commands", commands } } );
4604 }
4605 
generateDestroyCommand(std::string const & name,CommandData const & commandData) const4606 std::string VulkanHppGenerator::generateDestroyCommand( std::string const & name, CommandData const & commandData ) const
4607 {
4608   // special handling for destroy functions, filter out alias functions
4609   std::string commandName = generateCommandName( name, commandData.params, 1, m_tags );
4610   if ( commandData.alias.empty() && ( ( ( name.substr( 2, 7 ) == "Destroy" ) && ( commandName != "destroy" ) ) || ( name.substr( 2, 4 ) == "Free" ) ||
4611                                       ( name == "vkReleasePerformanceConfigurationINTEL" ) ) )
4612   {
4613     assert( 1 < commandData.params.size() );
4614     // make sure, the object to destroy/free/release is not optional in the shortened version!
4615     CommandData localCommandData        = commandData;
4616     localCommandData.params[1].optional = false;
4617 
4618     std::string destroyCommandString = generateCommand( name, localCommandData, 1, false );
4619     std::string shortenedName;
4620     if ( name.substr( 2, 7 ) == "Destroy" )
4621     {
4622       shortenedName = "destroy";
4623     }
4624     else if ( name.substr( 2, 4 ) == "Free" )
4625     {
4626       // enclose "free" in parenthesis to prevent interference with MSVC debug free
4627       shortenedName = "( free )";
4628     }
4629     else
4630     {
4631       assert( name == "vkReleasePerformanceConfigurationINTEL" );
4632       shortenedName = "release";
4633     }
4634     size_t pos = destroyCommandString.find( commandName );
4635     while ( pos != std::string::npos )
4636     {
4637       destroyCommandString.replace( pos, commandName.length(), shortenedName );
4638       pos = destroyCommandString.find( commandName, pos );
4639     }
4640     // we need to remove the default argument for the first argument, to prevent ambiguities!
4641     assert( 1 < localCommandData.params.size() );
4642     pos = destroyCommandString.find( localCommandData.params[1].name );  // skip the standard version of the function
4643     assert( pos != std::string::npos );
4644     pos = destroyCommandString.find( localCommandData.params[1].name,
4645                                      pos + 1 );  // get the argument to destroy in the advanced version
4646     assert( pos != std::string::npos );
4647     pos = destroyCommandString.find( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT", pos );
4648     if ( pos != std::string::npos )
4649     {
4650       destroyCommandString.erase( pos, strlen( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT" ) );
4651     }
4652     return "\n" + destroyCommandString;
4653   }
4654   return "";
4655 }
4656 
generateDispatchLoaderDynamicCommandAssignment(std::string const & commandName,CommandData const & commandData,std::string const & firstArg) const4657 std::string VulkanHppGenerator::generateDispatchLoaderDynamicCommandAssignment( std::string const & commandName,
4658                                                                                 CommandData const & commandData,
4659                                                                                 std::string const & firstArg ) const
4660 {
4661   if ( commandName == "vkGetInstanceProcAddr" )
4662   {
4663     // Don't overwite vkGetInstanceProcAddr with NULL.
4664     return "";
4665   }
4666   std::string str = "      " + commandName + " = PFN_" + commandName + "( vkGet" + ( ( firstArg == "device" ) ? "Device" : "Instance" ) + "ProcAddr( " +
4667                     firstArg + ", \"" + commandName + "\" ) );\n";
4668   // if this is an alias'ed function, use it as a fallback for the original one
4669   if ( !commandData.alias.empty() )
4670   {
4671     str += "      if ( !" + commandData.alias + " ) " + commandData.alias + " = " + commandName + ";\n";
4672   }
4673   return str;
4674 }
4675 
generateDispatchLoaderStaticCommands(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title) const4676 std::string VulkanHppGenerator::generateDispatchLoaderStaticCommands( std::vector<RequireData> const & requireData,
4677                                                                       std::set<std::string> &          listedCommands,
4678                                                                       std::string const &              title ) const
4679 {
4680   std::string str;
4681   for ( auto const & require : requireData )
4682   {
4683     for ( auto const & command : require.commands )
4684     {
4685       // some commands are listed for multiple extensions !
4686       if ( listedCommands.insert( command ).second )
4687       {
4688         auto commandIt = m_commands.find( command );
4689         assert( commandIt != m_commands.end() );
4690 
4691         str += "\n";
4692         std::string parameterList, parameters;
4693         assert( !commandIt->second.params.empty() );
4694         for ( auto param : commandIt->second.params )
4695         {
4696           parameterList += param.type.compose( "" ) + " " + param.name + generateCArraySizes( param.arraySizes ) + ", ";
4697           parameters += param.name + ", ";
4698         }
4699         assert( parameterList.ends_with( ", " ) && parameters.ends_with( ", " ) );
4700         parameterList.resize( parameterList.size() - 2 );
4701         parameters.resize( parameters.size() - 2 );
4702 
4703         const std::string commandTemplate = R"(
4704     ${returnType} ${commandName}( ${parameterList} ) const VULKAN_HPP_NOEXCEPT
4705     {
4706       return ::${commandName}( ${parameters} );
4707     }
4708 )";
4709 
4710         str += replaceWithMap( commandTemplate,
4711                                { { "commandName", commandIt->first },
4712                                  { "parameterList", parameterList },
4713                                  { "parameters", parameters },
4714                                  { "returnType", commandIt->second.returnType } } );
4715       }
4716     }
4717   }
4718   return addTitleAndProtection( title, str );
4719 }
4720 
generateEnum(std::pair<std::string,EnumData> const & enumData,std::string const & surroundingProtect) const4721 std::string VulkanHppGenerator::generateEnum( std::pair<std::string, EnumData> const & enumData, std::string const & surroundingProtect ) const
4722 {
4723   std::string baseType, bitmask;
4724   if ( enumData.second.isBitmask )
4725   {
4726     auto bitmaskIt =
4727       std::find_if( m_bitmasks.begin(), m_bitmasks.end(), [&enumData]( auto const & bitmask ) { return bitmask.second.requirements == enumData.first; } );
4728     assert( bitmaskIt != m_bitmasks.end() );
4729     baseType = " : " + bitmaskIt->first;
4730     bitmask  = generateBitmask( bitmaskIt, surroundingProtect );
4731   }
4732 
4733   std::string                        enumValues, previousEnter, previousLeave;
4734   std::map<std::string, std::string> valueToNameMap;
4735   for ( auto const & value : enumData.second.values )
4736   {
4737     // determine the values protect, if any
4738     std::string valueProtect = getProtect( value );
4739 
4740     // if the value's protect differs from the surrounding protect, generate protection code
4741     std::string enter, leave;
4742     if ( !valueProtect.empty() && ( valueProtect != surroundingProtect ) )
4743     {
4744       tie( enter, leave ) = generateProtection( valueProtect );
4745     }
4746     if ( previousEnter != enter )
4747     {
4748       enumValues += previousLeave + enter;
4749     }
4750     std::string valueName = generateEnumValueName( enumData.first, value.name, enumData.second.isBitmask, m_tags );
4751     enumValues += "    " + valueName + " = " + value.name + ",\n";
4752     assert( valueToNameMap.find( valueName ) == valueToNameMap.end() );
4753     valueToNameMap[valueName] = value.name;
4754 
4755     previousEnter = enter;
4756     previousLeave = leave;
4757   }
4758   enumValues += previousLeave;
4759 
4760   for ( auto const & alias : enumData.second.aliases )
4761   {
4762     std::string aliasName =
4763       generateEnumValueName( enumData.second.alias.empty() ? enumData.first : enumData.second.alias, alias.first, enumData.second.isBitmask, m_tags );
4764     // make sure to only list alias values that differ from all previous values
4765     auto valueToNameIt = valueToNameMap.find( aliasName );
4766     if ( valueToNameIt == valueToNameMap.end() )
4767     {
4768 #if !defined( NDEBUG )
4769       auto enumIt = std::find_if(
4770         enumData.second.values.begin(), enumData.second.values.end(), [&alias]( EnumValueData const & evd ) { return alias.second.name == evd.name; } );
4771       if ( enumIt == enumData.second.values.end() )
4772       {
4773         auto aliasIt = enumData.second.aliases.find( alias.second.name );
4774         assert( aliasIt != enumData.second.aliases.end() );
4775         auto nextAliasIt = enumData.second.aliases.find( aliasIt->second.name );
4776         while ( nextAliasIt != enumData.second.aliases.end() )
4777         {
4778           aliasIt     = nextAliasIt;
4779           nextAliasIt = enumData.second.aliases.find( aliasIt->second.name );
4780         }
4781         enumIt = std::find_if(
4782           enumData.second.values.begin(), enumData.second.values.end(), [&aliasIt]( EnumValueData const & evd ) { return aliasIt->second.name == evd.name; } );
4783       }
4784       assert( enumIt != enumData.second.values.end() );
4785       assert( enumIt->extension.empty() || generateProtection( getProtectFromTitle( enumIt->extension ) ).first.empty() );
4786 #endif
4787       enumValues += "    " + aliasName + " = " + alias.first + ",\n";
4788 
4789       // map the aliasName to the name of the base
4790       std::string baseName = findBaseName( alias.second.name, enumData.second.aliases );
4791       assert( std::find_if( enumData.second.values.begin(),
4792                             enumData.second.values.end(),
4793                             [&baseName]( EnumValueData const & evd ) { return evd.name == baseName; } ) != enumData.second.values.end() );
4794       valueToNameMap[aliasName] = baseName;
4795     }
4796 #if !defined( NDEBUG )
4797     else
4798     {
4799       // verify, that the identical value represents the identical name
4800       std::string baseName = findBaseName( alias.second.name, enumData.second.aliases );
4801       assert( std::find_if( enumData.second.values.begin(),
4802                             enumData.second.values.end(),
4803                             [&baseName]( EnumValueData const & evd ) { return evd.name == baseName; } ) != enumData.second.values.end() );
4804       assert( baseName == valueToNameIt->second );
4805     }
4806 #endif
4807   }
4808   if ( !enumValues.empty() )
4809   {
4810     size_t pos = enumValues.rfind( ',' );
4811     assert( pos != std::string::npos );
4812     enumValues.erase( pos, 1 );
4813     enumValues = "\n" + enumValues + "  ";
4814   }
4815 
4816   std::string enumUsing;
4817   if ( !enumData.second.alias.empty() )
4818   {
4819     enumUsing += "  using " + stripPrefix( enumData.second.alias, "Vk" ) + " = " + stripPrefix( enumData.first, "Vk" ) + ";\n";
4820   }
4821 
4822   const std::string enumTemplate = R"(  enum class ${enumName}${baseType}
4823   {${enumValues}};
4824 ${enumUsing}${bitmask})";
4825 
4826   return replaceWithMap( enumTemplate,
4827                          { { "baseType", baseType },
4828                            { "bitmask", bitmask },
4829                            { "enumName", stripPrefix( enumData.first, "Vk" ) },
4830                            { "enumUsing", enumUsing },
4831                            { "enumValues", enumValues } } );
4832 }
4833 
generateEnums() const4834 std::string VulkanHppGenerator::generateEnums() const
4835 {
4836   const std::string enumsTemplate = R"(
4837   //=============
4838   //=== ENUMs ===
4839   //=============
4840 
4841 ${enums}
4842 )";
4843 
4844   std::string           enums;
4845   std::set<std::string> listedEnums;
4846   for ( auto const & feature : m_features )
4847   {
4848     enums += generateEnums( feature.second.requireData, listedEnums, feature.first );
4849   }
4850   for ( auto const & extIt : m_extensionsByNumber )
4851   {
4852     enums += generateEnums( extIt.second->second.requireData, listedEnums, extIt.second->first );
4853   }
4854 
4855   return replaceWithMap( enumsTemplate, { { "enums", enums } } );
4856 }
4857 
4858 std::string
generateEnums(std::vector<RequireData> const & requireData,std::set<std::string> & listedEnums,std::string const & title) const4859   VulkanHppGenerator::generateEnums( std::vector<RequireData> const & requireData, std::set<std::string> & listedEnums, std::string const & title ) const
4860 {
4861   std::string surroundingProtect = getProtectFromTitle( title );
4862   std::string str;
4863   for ( auto const & require : requireData )
4864   {
4865     for ( auto const & type : require.types )
4866     {
4867       auto enumIt = m_enums.find( type );
4868       if ( ( enumIt != m_enums.end() ) && ( listedEnums.find( type ) == listedEnums.end() ) )
4869       {
4870         listedEnums.insert( type );
4871         str += "\n";
4872         str += generateEnum( *enumIt, surroundingProtect );
4873       }
4874     }
4875   }
4876   return addTitleAndProtection( title, str );
4877 }
4878 
generateEnumsToString() const4879 std::string VulkanHppGenerator::generateEnumsToString() const
4880 {
4881   // start with toHexString, which is used in all the to_string functions here!
4882   const std::string enumsToStringTemplate = R"(
4883   //=======================
4884   //=== ENUMs to_string ===
4885   //=======================
4886 
4887   VULKAN_HPP_INLINE std::string toHexString( uint32_t value )
4888   {
4889 #if __cpp_lib_format
4890     return std::format( "{:x}", value );
4891 #else
4892     std::stringstream stream;
4893     stream << std::hex << value;
4894     return stream.str();
4895 #endif
4896   }
4897 
4898 ${enumsToString}
4899 )";
4900 
4901   std::string           enumsToString;
4902   std::set<std::string> listedEnums;
4903   for ( auto const & feature : m_features )
4904   {
4905     enumsToString += generateEnumsToString( feature.second.requireData, listedEnums, feature.first );
4906   }
4907   for ( auto const & extIt : m_extensionsByNumber )
4908   {
4909     enumsToString += generateEnumsToString( extIt.second->second.requireData, listedEnums, extIt.second->first );
4910   }
4911 
4912   return replaceWithMap( enumsToStringTemplate, { { "enumsToString", enumsToString } } );
4913 }
4914 
generateEnumsToString(std::vector<RequireData> const & requireData,std::set<std::string> & listedEnums,std::string const & title) const4915 std::string VulkanHppGenerator::generateEnumsToString( std::vector<RequireData> const & requireData,
4916                                                        std::set<std::string> &          listedEnums,
4917                                                        std::string const &              title ) const
4918 {
4919   std::string str;
4920   for ( auto const & require : requireData )
4921   {
4922     for ( auto const & type : require.types )
4923     {
4924       auto enumIt = m_enums.find( type );
4925       if ( ( enumIt != m_enums.end() ) && ( listedEnums.find( type ) == listedEnums.end() ) )
4926       {
4927         listedEnums.insert( type );
4928 
4929         str += "\n";
4930         str += generateEnumToString( *enumIt );
4931       }
4932     }
4933   }
4934   return addTitleAndProtection( title, str );
4935 }
4936 
generateEnumInitializer(TypeInfo const & type,std::vector<std::string> const & arraySizes,std::vector<EnumValueData> const & values,bool bitmask) const4937 std::string VulkanHppGenerator::generateEnumInitializer( TypeInfo const &                   type,
4938                                                          std::vector<std::string> const &   arraySizes,
4939                                                          std::vector<EnumValueData> const & values,
4940                                                          bool                               bitmask ) const
4941 {
4942   // enum arguments might need special initialization
4943   assert( type.prefix.empty() && !values.empty() );
4944   std::string valueName = generateEnumValueName( type.type, values.front().name, bitmask, m_tags );
4945   std::string value     = generateNamespacedType( type.type ) + "::" + valueName;
4946   std::string str;
4947   if ( arraySizes.empty() )
4948   {
4949     str += value;
4950   }
4951   else
4952   {
4953     assert( arraySizes.size() == 1 );
4954     auto constIt = m_constants.find( arraySizes[0] );
4955     int  count   = std::stoi( ( constIt == m_constants.end() ) ? arraySizes[0] : constIt->second );
4956     assert( 1 < count );
4957     str += "{ { " + value;
4958     for ( int i = 1; i < count; i++ )
4959     {
4960       str += ", " + value;
4961     }
4962     str += " } }";
4963   }
4964   return str;
4965 }
4966 
generateEnumToString(std::pair<std::string,EnumData> const & enumData) const4967 std::string VulkanHppGenerator::generateEnumToString( std::pair<std::string, EnumData> const & enumData ) const
4968 {
4969   std::string enumName = stripPrefix( enumData.first, "Vk" );
4970   std::string functionBody;
4971   if ( enumData.second.values.empty() )
4972   {
4973     functionBody = R"x(    return "(void)";)x";
4974   }
4975   else
4976   {
4977     std::string cases, previousEnter, previousLeave;
4978     for ( auto const & value : enumData.second.values )
4979     {
4980       auto [enter, leave] = generateProtection( getProtect( value ) );
4981       if ( previousEnter != enter )
4982       {
4983         cases += previousLeave + enter;
4984       }
4985 
4986       const std::string caseTemplate = R"(      case ${enumName}::e${valueName} : return "${valueName}";
4987 )";
4988       cases += replaceWithMap(
4989         caseTemplate,
4990         { { "enumName", enumName }, { "valueName", generateEnumValueName( enumData.first, value.name, enumData.second.isBitmask, m_tags ).substr( 1 ) } } );
4991 
4992       previousEnter = enter;
4993       previousLeave = leave;
4994     }
4995     cases += previousLeave;
4996 
4997     const std::string functionBodyTemplate =
4998       R"x(    switch ( value )
4999     {
5000 ${cases}      default: return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString( static_cast<uint32_t>( value ) ) + " )";
5001     }
5002 )x";
5003 
5004     functionBody = replaceWithMap( functionBodyTemplate, { { "cases", cases } } );
5005   }
5006 
5007   const std::string enumToStringTemplate = R"(
5008   VULKAN_HPP_INLINE std::string to_string( ${enumName}${argument} )
5009   {
5010 ${functionBody}
5011   }
5012 )";
5013 
5014   return replaceWithMap( enumToStringTemplate,
5015                          { { "argument", enumData.second.values.empty() ? "" : " value" }, { "enumName", enumName }, { "functionBody", functionBody } } );
5016 }
5017 
generateFailureCheck(std::vector<std::string> const & successCodes) const5018 std::string VulkanHppGenerator::generateFailureCheck( std::vector<std::string> const & successCodes ) const
5019 {
5020   assert( !successCodes.empty() );
5021   std::string failureCheck = "result != " + generateSuccessCode( successCodes[0], m_tags );
5022   if ( 1 < successCodes.size() )
5023   {
5024     failureCheck = "( " + failureCheck + " )";
5025     for ( size_t i = 1; i < successCodes.size(); ++i )
5026     {
5027       failureCheck += "&& ( result != " + generateSuccessCode( successCodes[i], m_tags ) + " )";
5028     }
5029   }
5030   return failureCheck;
5031 }
5032 
generateFormatTraits() const5033 std::string VulkanHppGenerator::generateFormatTraits() const
5034 {
5035   if ( m_formats.empty() )
5036   {
5037     return "";
5038   }
5039 
5040   const std::string formatTraitsTemplate = R"(
5041   //=====================
5042   //=== Format Traits ===
5043   //=====================
5044 
5045   // The three-dimensional extent of a texel block.
5046   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 std::array<uint8_t, 3> blockExtent( VULKAN_HPP_NAMESPACE::Format format )
5047   {
5048     switch( format )
5049     {
5050 ${blockExtentCases}
5051       default: return {{1, 1, 1 }};
5052     }
5053   }
5054 
5055   // The texel block size in bytes.
5056   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t blockSize( VULKAN_HPP_NAMESPACE::Format format )
5057   {
5058     switch( format )
5059     {
5060 ${blockSizeCases}
5061       default : VULKAN_HPP_ASSERT( false ); return 0;
5062     }
5063   }
5064 
5065   // The class of the format (can't be just named "class"!)
5066   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * compatibilityClass( VULKAN_HPP_NAMESPACE::Format format )
5067   {
5068     switch( format )
5069     {
5070 ${classCases}
5071       default : VULKAN_HPP_ASSERT( false ); return "";
5072     }
5073   }
5074 
5075   // The number of bits in this component, if not compressed, otherwise 0.
5076   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t componentBits( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5077   {
5078     switch( format )
5079     {
5080 ${componentBitsCases}
5081       default: return 0;
5082     }
5083   }
5084 
5085   // The number of components of this format.
5086   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t componentCount( VULKAN_HPP_NAMESPACE::Format format )
5087   {
5088     switch( format )
5089     {
5090 ${componentCountCases}
5091       default: return 0;
5092     }
5093   }
5094 
5095   // The name of the component
5096   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * componentName( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5097   {
5098     switch( format )
5099     {
5100 ${componentNameCases}
5101       default: return "";
5102     }
5103   }
5104 
5105   // The numeric format of the component
5106   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * componentNumericFormat( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5107   {
5108     switch( format )
5109     {
5110 ${componentNumericFormatCases}
5111       default: return "";
5112     }
5113   }
5114 
5115   // The plane this component lies in.
5116   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t componentPlaneIndex( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5117   {
5118     switch( format )
5119     {
5120 ${componentPlaneIndexCases}
5121       default: return 0;
5122     }
5123   }
5124 
5125   // True, if the components of this format are compressed, otherwise false.
5126   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 bool componentsAreCompressed( VULKAN_HPP_NAMESPACE::Format format )
5127   {
5128     switch( format )
5129     {
5130 ${componentsAreCompressedCases}
5131         return true;
5132       default: return false;
5133     }
5134   }
5135 
5136   // A textual description of the compression scheme, or an empty string if it is not compressed
5137   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * compressionScheme( VULKAN_HPP_NAMESPACE::Format format )
5138   {
5139     switch( format )
5140     {
5141 ${compressionSchemeCases}
5142       default: return "";
5143     }
5144   }
5145 
5146   // True, if this format is a compressed one.
5147   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 bool isCompressed( VULKAN_HPP_NAMESPACE::Format format )
5148   {
5149     return ( *VULKAN_HPP_NAMESPACE::compressionScheme( format ) != 0 );
5150   }
5151 
5152   // The number of bits into which the format is packed. A single image element in this format
5153   // can be stored in the same space as a scalar type of this bit width.
5154   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t packed( VULKAN_HPP_NAMESPACE::Format format )
5155   {
5156     switch( format )
5157     {
5158 ${packedCases}
5159       default: return 0;
5160     }
5161   }
5162 
5163   // The single-plane format that this plane is compatible with.
5164   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_NAMESPACE::Format planeCompatibleFormat( VULKAN_HPP_NAMESPACE::Format format, uint8_t plane )
5165   {
5166     switch( format )
5167     {
5168 ${planeCompatibleCases}
5169       default: VULKAN_HPP_ASSERT( plane == 0 ); return format;
5170     }
5171   }
5172 
5173   // The number of image planes of this format.
5174   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t planeCount( VULKAN_HPP_NAMESPACE::Format format )
5175   {
5176     switch( format )
5177     {
5178 ${planeCountCases}
5179       default: return 1;
5180     }
5181   }
5182 
5183   // The relative height of this plane. A value of k means that this plane is 1/k the height of the overall format.
5184   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t planeHeightDivisor( VULKAN_HPP_NAMESPACE::Format format, uint8_t plane )
5185   {
5186     switch( format )
5187     {
5188 ${planeHeightDivisorCases}
5189       default: VULKAN_HPP_ASSERT( plane == 0 ); return 1;
5190     }
5191   }
5192 
5193   // The relative width of this plane. A value of k means that this plane is 1/k the width of the overall format.
5194   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t planeWidthDivisor( VULKAN_HPP_NAMESPACE::Format format, uint8_t plane )
5195   {
5196     switch( format )
5197     {
5198 ${planeWidthDivisorCases}
5199       default: VULKAN_HPP_ASSERT( plane == 0 ); return 1;
5200     }
5201   }
5202 
5203   // The number of texels in a texel block.
5204   VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t texelsPerBlock( VULKAN_HPP_NAMESPACE::Format format )
5205   {
5206     switch( format )
5207     {
5208 ${texelsPerBlockCases}
5209       default: VULKAN_HPP_ASSERT( false ); return 0;
5210     }
5211   }
5212 )";
5213 
5214   auto formatIt = m_enums.find( "VkFormat" );
5215   assert( formatIt != m_enums.end() );
5216   assert( formatIt->second.values.front().name == "VK_FORMAT_UNDEFINED" );
5217 
5218   std::string blockSizeCases, blockExtentCases, classCases, componentBitsCases, componentCountCases, componentNameCases, componentNumericFormatCases,
5219     componentPlaneIndexCases, componentsAreCompressedCases, compressionSchemeCases, packedCases, planeCompatibleCases, planeCountCases, planeHeightDivisorCases,
5220     planeWidthDivisorCases, texelsPerBlockCases;
5221   for ( auto formatValuesIt = std::next( formatIt->second.values.begin() ); formatValuesIt != formatIt->second.values.end(); ++formatValuesIt )
5222   {
5223     auto traitIt = m_formats.find( formatValuesIt->name );
5224     assert( traitIt != m_formats.end() );
5225     std::string caseString = "      case VULKAN_HPP_NAMESPACE::Format::" + generateEnumValueName( "VkFormat", traitIt->first, false, m_tags ) + ":";
5226 
5227     blockSizeCases += caseString + " return " + traitIt->second.blockSize + ";\n";
5228 
5229     if ( !traitIt->second.blockExtent.empty() )
5230     {
5231       std::vector<std::string> blockExtent = tokenize( traitIt->second.blockExtent, "," );
5232       assert( blockExtent.size() == 3 );
5233       blockExtentCases += caseString + " return {{ " + blockExtent[0] + ", " + blockExtent[1] + ", " + blockExtent[2] + " }};\n";
5234     }
5235 
5236     classCases += caseString + " return \"" + traitIt->second.classAttribute + "\";\n";
5237 
5238     if ( traitIt->second.components.front().bits != "compressed" )
5239     {
5240       const std::string componentBitsCaseTemplate = R"(${caseString}
5241         switch( component )
5242         {
5243 ${componentCases}
5244           default: VULKAN_HPP_ASSERT( false ); return 0;
5245         }
5246 )";
5247 
5248       std::string componentCases;
5249       for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5250       {
5251         componentCases += "          case " + std::to_string( i ) + ": return " + traitIt->second.components[i].bits + ";\n";
5252       }
5253       componentCases.pop_back();
5254       componentBitsCases += replaceWithMap( componentBitsCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5255     }
5256 
5257     componentCountCases += caseString + " return " + std::to_string( traitIt->second.components.size() ) + ";\n";
5258 
5259     {
5260       const std::string componentNameCaseTemplate = R"(${caseString}
5261         switch( component )
5262         {
5263 ${componentCases}
5264           default: VULKAN_HPP_ASSERT( false ); return "";
5265         }
5266 )";
5267 
5268       std::string componentCases;
5269       for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5270       {
5271         componentCases += "          case " + std::to_string( i ) + ": return \"" + traitIt->second.components[i].name + "\";\n";
5272       }
5273       componentCases.pop_back();
5274       componentNameCases += replaceWithMap( componentNameCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5275     }
5276 
5277     {
5278       const std::string componentNumericFormatCaseTemplate = R"(${caseString}
5279         switch( component )
5280         {
5281 ${componentCases}
5282           default: VULKAN_HPP_ASSERT( false ); return "";
5283         }
5284 )";
5285 
5286       std::string componentCases;
5287       for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5288       {
5289         componentCases += "          case " + std::to_string( i ) + ": return \"" + traitIt->second.components[i].numericFormat + "\";\n";
5290       }
5291       componentCases.pop_back();
5292       componentNumericFormatCases +=
5293         replaceWithMap( componentNumericFormatCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5294     }
5295 
5296     if ( !traitIt->second.components.front().planeIndex.empty() )
5297     {
5298       const std::string componentPlaneIndexCaseTemplate = R"(${caseString}
5299         switch( component )
5300         {
5301 ${componentCases}
5302           default: VULKAN_HPP_ASSERT( false ); return 0;
5303         }
5304 )";
5305 
5306       std::string componentCases;
5307       for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5308       {
5309         componentCases += "          case " + std::to_string( i ) + ": return " + traitIt->second.components[i].planeIndex + ";\n";
5310       }
5311       componentCases.pop_back();
5312       componentPlaneIndexCases += replaceWithMap( componentPlaneIndexCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5313     }
5314 
5315     if ( traitIt->second.components.front().bits == "compressed" )
5316     {
5317       componentsAreCompressedCases += caseString + "\n";
5318     }
5319 
5320     if ( !traitIt->second.compressed.empty() )
5321     {
5322       compressionSchemeCases += caseString + " return \"" + traitIt->second.compressed + "\";\n";
5323     }
5324 
5325     if ( !traitIt->second.packed.empty() )
5326     {
5327       packedCases += caseString + " return " + traitIt->second.packed + ";\n";
5328     }
5329 
5330     if ( !traitIt->second.planes.empty() )
5331     {
5332       const std::string planeCompatibleCaseTemplate = R"(${caseString}
5333         switch( plane )
5334         {
5335 ${compatibleCases}
5336           default: VULKAN_HPP_ASSERT( false ); return VULKAN_HPP_NAMESPACE::Format::eUndefined;
5337         }
5338 )";
5339 
5340       const std::string planeHeightDivisorCaseTemplate = R"(${caseString}
5341         switch( plane )
5342         {
5343 ${heightDivisorCases}
5344           default: VULKAN_HPP_ASSERT( false ); return 1;
5345         }
5346 )";
5347 
5348       const std::string planeWidthDivisorCaseTemplate = R"(${caseString}
5349         switch( plane )
5350         {
5351 ${widthDivisorCases}
5352           default: VULKAN_HPP_ASSERT( false ); return 1;
5353         }
5354 )";
5355 
5356       std::string compatibleCases, heightDivisorCases, widthDivisorCases;
5357       for ( size_t i = 0; i < traitIt->second.planes.size(); ++i )
5358       {
5359         compatibleCases += "          case " + std::to_string( i ) + ": return VULKAN_HPP_NAMESPACE::Format::" +
5360                            generateEnumValueName( "VkFormat", traitIt->second.planes[i].compatible, false, m_tags ) + ";\n";
5361         heightDivisorCases += "          case " + std::to_string( i ) + ": return " + traitIt->second.planes[i].heightDivisor + ";\n";
5362         widthDivisorCases += "          case " + std::to_string( i ) + ": return " + traitIt->second.planes[i].widthDivisor + ";\n";
5363       }
5364       compatibleCases.pop_back();
5365       heightDivisorCases.pop_back();
5366       widthDivisorCases.pop_back();
5367 
5368       planeCompatibleCases += replaceWithMap( planeCompatibleCaseTemplate, { { "caseString", caseString }, { "compatibleCases", compatibleCases } } );
5369 
5370       planeCountCases += caseString + " return " + std::to_string( traitIt->second.planes.size() ) + ";\n";
5371 
5372       planeHeightDivisorCases +=
5373         replaceWithMap( planeHeightDivisorCaseTemplate, { { "caseString", caseString }, { "heightDivisorCases", heightDivisorCases } } );
5374 
5375       planeWidthDivisorCases += replaceWithMap( planeWidthDivisorCaseTemplate, { { "caseString", caseString }, { "widthDivisorCases", widthDivisorCases } } );
5376     }
5377 
5378     texelsPerBlockCases += caseString + " return " + traitIt->second.texelsPerBlock + ";\n";
5379   }
5380 
5381   return replaceWithMap( formatTraitsTemplate,
5382                          { { "blockExtentCases", blockExtentCases },
5383                            { "blockSizeCases", blockSizeCases },
5384                            { "classCases", classCases },
5385                            { "componentBitsCases", componentBitsCases },
5386                            { "componentCountCases", componentCountCases },
5387                            { "componentNameCases", componentNameCases },
5388                            { "componentNumericFormatCases", componentNumericFormatCases },
5389                            { "componentPlaneIndexCases", componentPlaneIndexCases },
5390                            { "componentsAreCompressedCases", componentsAreCompressedCases },
5391                            { "compressionSchemeCases", compressionSchemeCases },
5392                            { "packedCases", packedCases },
5393                            { "planeCompatibleCases", planeCompatibleCases },
5394                            { "planeCountCases", planeCountCases },
5395                            { "planeHeightDivisorCases", planeHeightDivisorCases },
5396                            { "planeWidthDivisorCases", planeWidthDivisorCases },
5397                            { "texelsPerBlockCases", texelsPerBlockCases } } );
5398 }
5399 
generateFunctionPointerCheck(std::string const & function,std::string const & referencedIn) const5400 std::string VulkanHppGenerator::generateFunctionPointerCheck( std::string const & function, std::string const & referencedIn ) const
5401 {
5402   std::string functionPointerCheck;
5403   if ( m_extensions.find( referencedIn ) != m_extensions.end() )
5404   {
5405     std::string message  = "Function <" + function + "> needs extension <" + referencedIn + "> enabled!";
5406     functionPointerCheck = "VULKAN_HPP_ASSERT( getDispatcher()->" + function + " && \"" + message + "\" );";
5407   }
5408   return functionPointerCheck;
5409 }
5410 
generateHandle(std::pair<std::string,HandleData> const & handleData,std::set<std::string> & listedHandles) const5411 std::string VulkanHppGenerator::generateHandle( std::pair<std::string, HandleData> const & handleData, std::set<std::string> & listedHandles ) const
5412 {
5413   assert( listedHandles.find( handleData.first ) == listedHandles.end() );
5414 
5415   // first check for any handle that needs to be listed before this one
5416   std::string str = generateHandleDependencies( handleData, listedHandles );
5417 
5418   // list the commands of this handle
5419   if ( handleData.first.empty() )
5420   {
5421     // the free functions, not bound to any handle
5422     str += generateHandleEmpty( handleData.second );
5423   }
5424   else
5425   {
5426     // append any forward declaration of Deleters used by this handle
5427     if ( !handleData.second.childrenHandles.empty() )
5428     {
5429       str += generateUniqueTypes( handleData.first, handleData.second.childrenHandles );
5430     }
5431     else if ( handleData.first == "VkPhysicalDevice" )
5432     {
5433       // special handling for class Device, as it's created from PhysicalDevice, but destroys itself
5434       str += generateUniqueTypes( "", { "VkDevice" } );
5435     }
5436 
5437     // list all the commands that are mapped to members of this class
5438     std::string commands = generateHandleCommandDeclarations( handleData.second.commands );
5439 
5440     // create CPPType template specialization and the debugReportObjectType
5441     std::string valueName = handleData.second.objTypeEnum;
5442     valueName             = valueName.replace( 3, 0, "DEBUG_REPORT_" ) + "_EXT";
5443     auto enumIt           = m_enums.find( "VkDebugReportObjectTypeEXT" );
5444     assert( enumIt != m_enums.end() );
5445     auto valueIt =
5446       std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&valueName]( EnumValueData const & evd ) { return valueName == evd.name; } );
5447 
5448     std::string className = stripPrefix( handleData.first, "Vk" );
5449     std::string cppType, debugReportObjectType;
5450     if ( valueIt == enumIt->second.values.end() )
5451     {
5452       debugReportObjectType = "eUnknown";
5453     }
5454     else
5455     {
5456       static const std::string cppTypeFromDebugReportObjectTypeEXTTemplate = R"(
5457   template <>
5458   struct CppType<VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT, VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT::e${className}>
5459   {
5460     using Type = VULKAN_HPP_NAMESPACE::${className};
5461   };
5462 )";
5463       cppType               = replaceWithMap( cppTypeFromDebugReportObjectTypeEXTTemplate, { { "className", className } } );
5464       debugReportObjectType = generateEnumValueName( enumIt->first, valueIt->name, false, m_tags );
5465     }
5466 
5467     auto [enter, leave] = generateProtection( handleData.second.alias.empty() ? getProtectFromType( handleData.first ) : "" );
5468 
5469     assert( !handleData.second.objTypeEnum.empty() );
5470     enumIt = m_enums.find( "VkObjectType" );
5471     assert( enumIt != m_enums.end() );
5472     valueIt = std::find_if( enumIt->second.values.begin(),
5473                             enumIt->second.values.end(),
5474                             [&handleData]( EnumValueData const & evd ) { return evd.name == handleData.second.objTypeEnum; } );
5475     assert( valueIt != enumIt->second.values.end() );
5476     std::string usingAlias;
5477     if ( !handleData.second.alias.empty() )
5478     {
5479       usingAlias += "  using " + stripPrefix( handleData.second.alias, "Vk" ) + " = " + stripPrefix( handleData.first, "Vk" ) + ";\n";
5480     }
5481 
5482     const std::string typesafeExplicitKeyword          = handleData.second.isDispatchable ? "" : "VULKAN_HPP_TYPESAFE_EXPLICIT ";
5483     const std::string typesafeConversionConditional    = handleData.second.isDispatchable ? "" : "#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n";
5484     const std::string typesafeConversionConditionalEnd = handleData.second.isDispatchable ? "" : "#endif\n";
5485 
5486     static const std::string templateString = R"(
5487 ${enter}  class ${className}
5488   {
5489   public:
5490     using CType = Vk${className};
5491     using NativeType = Vk${className};
5492 
5493     static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::ObjectType objectType = VULKAN_HPP_NAMESPACE::ObjectType::${objTypeEnum};
5494     static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT debugReportObjectType = VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT::${debugReportObjectType};
5495 
5496   public:
5497     VULKAN_HPP_CONSTEXPR ${className}() = default;
5498     VULKAN_HPP_CONSTEXPR ${className}( std::nullptr_t ) VULKAN_HPP_NOEXCEPT
5499     {}
5500     ${typesafeExplicitKeyword}${className}( Vk${className} ${memberName} ) VULKAN_HPP_NOEXCEPT
5501       : m_${memberName}( ${memberName} )
5502     {}
5503 
5504 ${typesafeConversionConditional}    ${className} & operator=(Vk${className} ${memberName}) VULKAN_HPP_NOEXCEPT
5505     {
5506       m_${memberName} = ${memberName};
5507       return *this;
5508     }
5509 ${typesafeConversionConditionalEnd}
5510     ${className} & operator=( std::nullptr_t ) VULKAN_HPP_NOEXCEPT
5511     {
5512       m_${memberName} = {};
5513       return *this;
5514     }
5515 
5516 #if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)
5517     auto operator<=>( ${className} const & ) const = default;
5518 #else
5519     bool operator==( ${className} const & rhs ) const VULKAN_HPP_NOEXCEPT
5520     {
5521       return m_${memberName} == rhs.m_${memberName};
5522     }
5523 
5524     bool operator!=(${className} const & rhs ) const VULKAN_HPP_NOEXCEPT
5525     {
5526       return m_${memberName} != rhs.m_${memberName};
5527     }
5528 
5529     bool operator<(${className} const & rhs ) const VULKAN_HPP_NOEXCEPT
5530     {
5531       return m_${memberName} < rhs.m_${memberName};
5532     }
5533 #endif
5534 ${commands}
5535     ${typesafeExplicitKeyword}operator Vk${className}() const VULKAN_HPP_NOEXCEPT
5536     {
5537       return m_${memberName};
5538     }
5539 
5540     explicit operator bool() const VULKAN_HPP_NOEXCEPT
5541     {
5542       return m_${memberName} != VK_NULL_HANDLE;
5543     }
5544 
5545     bool operator!() const VULKAN_HPP_NOEXCEPT
5546     {
5547       return m_${memberName} == VK_NULL_HANDLE;
5548     }
5549 
5550   private:
5551     Vk${className} m_${memberName} = {};
5552   };
5553 
5554   template <>
5555   struct CppType<VULKAN_HPP_NAMESPACE::ObjectType, VULKAN_HPP_NAMESPACE::ObjectType::${objTypeEnum}>
5556   {
5557     using Type = VULKAN_HPP_NAMESPACE::${className};
5558   };
5559 
5560 ${CppType}
5561 
5562   template <>
5563   struct isVulkanHandleType<VULKAN_HPP_NAMESPACE::${className}>
5564   {
5565     static VULKAN_HPP_CONST_OR_CONSTEXPR bool value = true;
5566   };
5567 ${usingAlias}${leave})";
5568 
5569     str += replaceWithMap( templateString,
5570                            { { "className", className },
5571                              { "commands", commands },
5572                              { "CppType", cppType },
5573                              { "debugReportObjectType", debugReportObjectType },
5574                              { "enter", enter },
5575                              { "leave", leave },
5576                              { "memberName", startLowerCase( stripPrefix( handleData.first, "Vk" ) ) },
5577                              { "objTypeEnum", generateEnumValueName( enumIt->first, valueIt->name, false, m_tags ) },
5578                              { "usingAlias", usingAlias },
5579                              { "typesafeExplicitKeyword", typesafeExplicitKeyword },
5580                              { "typesafeConversionConditional", typesafeConversionConditional },
5581                              { "typesafeConversionConditionalEnd", typesafeConversionConditionalEnd } } );
5582   }
5583 
5584   listedHandles.insert( handleData.first );
5585   return str;
5586 }
5587 
generateHandleCommandDeclarations(std::set<std::string> const & commands) const5588 std::string VulkanHppGenerator::generateHandleCommandDeclarations( std::set<std::string> const & commands ) const
5589 {
5590   std::string           str;
5591   std::set<std::string> listedCommands;  // some commands are listed with more than one extension!
5592   for ( auto const & feature : m_features )
5593   {
5594     std::vector<std::string> commandNames = selectCommandsByHandle( feature.second.requireData, commands, listedCommands );
5595     if ( !commandNames.empty() )
5596     {
5597       str += "\n  //=== " + feature.first + " ===\n";
5598       for ( auto const & command : commandNames )
5599       {
5600         auto commandIt = m_commands.find( command );
5601         assert( commandIt != m_commands.end() );
5602 
5603         str += "\n";
5604         str += generateCommand( commandIt->first, commandIt->second, 1, false );
5605         str += generateDestroyCommand( commandIt->first, commandIt->second );
5606       }
5607     }
5608   }
5609   for ( auto const & extIt : m_extensionsByNumber )
5610   {
5611     std::vector<std::string> commandNames = selectCommandsByHandle( extIt.second->second.requireData, commands, listedCommands );
5612     if ( !commandNames.empty() )
5613     {
5614       auto [enter, leave] = generateProtection( getProtectFromTitle( extIt.second->first ) );
5615       str += "\n" + enter + "  //=== " + extIt.second->first + " ===\n";
5616       for ( auto const & command : commandNames )
5617       {
5618         auto commandIt = m_commands.find( command );
5619         assert( commandIt != m_commands.end() );
5620 
5621         std::string commandString;
5622         std::string commandName = generateCommandName( commandIt->first, commandIt->second.params, 1, m_tags );
5623         str += "\n";
5624         str += generateCommand( commandIt->first, commandIt->second, 1, false );
5625         str += generateDestroyCommand( commandIt->first, commandIt->second );
5626       }
5627       str += leave;
5628     }
5629   }
5630   return str;
5631 }
5632 
generateHandleDependencies(std::pair<std::string,HandleData> const & handleData,std::set<std::string> & listedHandles) const5633 std::string VulkanHppGenerator::generateHandleDependencies( std::pair<std::string, HandleData> const & handleData, std::set<std::string> & listedHandles ) const
5634 {
5635   std::string str;
5636   for ( auto const & command : handleData.second.commands )
5637   {
5638     auto commandIt = m_commands.find( command );
5639     assert( commandIt != m_commands.end() );
5640     for ( auto const & parameter : commandIt->second.params )
5641     {
5642       auto handleIt = m_handles.find( parameter.type.type );
5643       if ( ( handleIt != m_handles.end() ) && ( parameter.type.type != handleData.first ) &&
5644            ( listedHandles.find( parameter.type.type ) == listedHandles.end() ) )
5645       {
5646         str += generateHandle( *handleIt, listedHandles );
5647       }
5648     }
5649   }
5650   return str;
5651 }
5652 
generateHandleEmpty(HandleData const & handleData) const5653 std::string VulkanHppGenerator::generateHandleEmpty( HandleData const & handleData ) const
5654 {
5655   std::string           str;
5656   std::set<std::string> listedCommands;  // some commands are listed with more than one extension !
5657   for ( auto const & feature : m_features )
5658   {
5659     std::vector<std::string> commands = selectCommandsByHandle( feature.second.requireData, handleData.commands, listedCommands );
5660     if ( !commands.empty() )
5661     {
5662       str += "\n  //=== " + feature.first + " ===\n";
5663       for ( auto const & command : commands )
5664       {
5665         auto commandIt = m_commands.find( command );
5666         assert( commandIt != m_commands.end() );
5667         if ( commandIt->first == "vkCreateInstance" )
5668         {
5669           // special handling for createInstance, as we need to explicitly place the forward declarations and the
5670           // deleter classes here
5671 #if !defined( NDEBUG )
5672           auto handleIt = m_handles.find( "" );
5673           assert( ( handleIt != m_handles.end() ) && ( handleIt->second.childrenHandles.size() == 2 ) );
5674           assert( handleIt->second.childrenHandles.find( "VkInstance" ) != handleIt->second.childrenHandles.end() );
5675 #endif
5676 
5677           str += generateUniqueTypes( "", { "VkInstance" } );
5678         }
5679         str += "\n";
5680 
5681         str += generateCommand( commandIt->first, commandIt->second, 0, false );
5682       }
5683     }
5684   }
5685 #if !defined( NDEBUG )
5686   for ( auto const & extIt : m_extensionsByNumber )
5687   {
5688     assert( selectCommandsByHandle( extIt.second->second.requireData, handleData.commands, listedCommands ).empty() );
5689   }
5690 #endif
5691   return str;
5692 }
5693 
generateHandleHashStructures(std::vector<RequireData> const & requireData,std::string const & title) const5694 std::string VulkanHppGenerator::generateHandleHashStructures( std::vector<RequireData> const & requireData, std::string const & title ) const
5695 {
5696   const std::string hashTemplate = R"(
5697   template <> struct hash<VULKAN_HPP_NAMESPACE::${type}>
5698   {
5699     std::size_t operator()(VULKAN_HPP_NAMESPACE::${type} const & ${name}) const VULKAN_HPP_NOEXCEPT
5700     {
5701       return std::hash<Vk${type}>{}(static_cast<Vk${type}>(${name}));
5702     }
5703   };
5704 )";
5705 
5706   std::string str;
5707   for ( auto const & require : requireData )
5708   {
5709     for ( auto const & type : require.types )
5710     {
5711       auto handleIt = m_handles.find( type );
5712       if ( handleIt != m_handles.end() )
5713       {
5714         std::string handleType = stripPrefix( handleIt->first, "Vk" );
5715         std::string handleName = startLowerCase( handleType );
5716         str += replaceWithMap( hashTemplate, { { "name", handleName }, { "type", handleType } } );
5717       }
5718     }
5719   }
5720   return addTitleAndProtection( title, str );
5721 }
5722 
generateHandleHashStructures() const5723 std::string VulkanHppGenerator::generateHandleHashStructures() const
5724 {
5725   const std::string hashesTemplate = R"(
5726   //===================================
5727   //=== HASH structures for handles ===
5728   //===================================
5729 
5730 ${hashes}
5731 )";
5732 
5733   std::string hashes;
5734   for ( auto const & feature : m_features )
5735   {
5736     hashes += generateHandleHashStructures( feature.second.requireData, feature.first );
5737   }
5738   for ( auto const & extIt : m_extensionsByNumber )
5739   {
5740     hashes += generateHandleHashStructures( extIt.second->second.requireData, extIt.second->first );
5741   }
5742   return replaceWithMap( hashesTemplate, { { "hashes", hashes } } );
5743 }
5744 
generateHandles() const5745 std::string VulkanHppGenerator::generateHandles() const
5746 {
5747   // Note: reordering structs or handles by features and extensions is not possible!
5748   std::string str = R"(
5749   //===============
5750   //=== HANDLEs ===
5751   //===============
5752 
5753   template <typename Type>
5754   struct isVulkanHandleType
5755   {
5756     static VULKAN_HPP_CONST_OR_CONSTEXPR bool value = false;
5757   };
5758 )";
5759 
5760   std::set<std::string> listedHandles;
5761   for ( auto const & handle : m_handles )
5762   {
5763     if ( listedHandles.find( handle.first ) == listedHandles.end() )
5764     {
5765       str += generateHandle( handle, listedHandles );
5766     }
5767   }
5768   return str;
5769 }
5770 
generateIndexTypeTraits() const5771 std::string VulkanHppGenerator::generateIndexTypeTraits() const
5772 {
5773   const std::string indexTypeTraitsTemplate = R"(
5774   //=========================
5775   //=== Index Type Traits ===
5776   //=========================
5777 
5778   template<typename T>
5779   struct IndexTypeValue
5780   {};
5781 
5782 ${indexTypeTraits}
5783 )";
5784 
5785   auto indexType = m_enums.find( "VkIndexType" );
5786   assert( indexType != m_enums.end() );
5787 
5788   std::string           indexTypeTraits;
5789   std::set<std::string> listedCppTypes;
5790   for ( auto const & value : indexType->second.values )
5791   {
5792     std::string valueName = generateEnumValueName( indexType->first, value.name, false, m_tags );
5793     std::string cppType;
5794     if ( !valueName.starts_with( "eNone" ) )
5795     {
5796       // get the bit count out of the value Name (8, 16, 32, ... ) and generate the cppType (uint8_t,...)
5797       assert( valueName.starts_with( "eUint" ) );
5798       auto beginDigit = valueName.begin() + strlen( "eUint" );
5799       assert( isdigit( *beginDigit ) );
5800       auto endDigit = std::find_if_not( beginDigit, valueName.end(), []( std::string::value_type c ) { return isdigit( c ); } );
5801       cppType       = "uint" + valueName.substr( strlen( "eUint" ), endDigit - beginDigit ) + "_t";
5802     }
5803 
5804     if ( !cppType.empty() )
5805     {
5806       if ( listedCppTypes.insert( cppType ).second )
5807       {
5808         // IndexType traits aren't necessarily invertible.
5809         // The Type -> Enum translation will only occur for the first prefixed enum value.
5810         // A hypothetical extension to this enum with a conflicting prefix will use the core spec value.
5811         const std::string typeToEnumTemplate = R"(
5812   template <>
5813   struct IndexTypeValue<${cppType}>
5814   {
5815     static VULKAN_HPP_CONST_OR_CONSTEXPR IndexType value = IndexType::${valueName};
5816   };
5817 )";
5818         indexTypeTraits += replaceWithMap( typeToEnumTemplate, { { "cppType", cppType }, { "valueName", valueName } } );
5819       }
5820 
5821       // Enum -> Type translations are always able to occur.
5822       const std::string enumToTypeTemplate = R"(
5823   template <>
5824   struct CppType<IndexType, IndexType::${valueName}>
5825   {
5826     using Type = ${cppType};
5827   };
5828 )";
5829       indexTypeTraits += replaceWithMap( enumToTypeTemplate, { { "cppType", cppType }, { "valueName", valueName } } );
5830     }
5831   }
5832 
5833   return replaceWithMap( indexTypeTraitsTemplate, { { "indexTypeTraits", indexTypeTraits } } );
5834 }
5835 
generateLenInitializer(std::vector<MemberData>::const_iterator mit,std::map<std::vector<MemberData>::const_iterator,std::vector<std::vector<MemberData>::const_iterator>>::const_iterator litit,bool mutualExclusiveLens) const5836 std::string VulkanHppGenerator::generateLenInitializer(
5837   std::vector<MemberData>::const_iterator                                                                                 mit,
5838   std::map<std::vector<MemberData>::const_iterator, std::vector<std::vector<MemberData>::const_iterator>>::const_iterator litit,
5839   bool                                                                                                                    mutualExclusiveLens ) const
5840 {
5841   std::string initializer;
5842   if ( mutualExclusiveLens )
5843   {
5844     // there are multiple mutually exclusive arrays related to this len
5845     for ( size_t i = 0; i + 1 < litit->second.size(); i++ )
5846     {
5847       auto        arrayIt      = litit->second[i];
5848       std::string argumentName = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + "_";
5849       initializer += "!" + argumentName + ".empty() ? " + argumentName + ".size() : ";
5850     }
5851     auto        arrayIt      = litit->second.back();
5852     std::string argumentName = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + "_";
5853     initializer += argumentName + ".size()";
5854   }
5855   else
5856   {
5857     auto arrayIt = litit->second.front();
5858     assert( ( arrayIt->len.front() == litit->first->name ) || ( ( arrayIt->len.front() == "codeSize / 4" ) && ( litit->first->name == "codeSize" ) ) );
5859 
5860     assert( arrayIt->name.starts_with( "p" ) );
5861     std::string argumentName = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + "_";
5862 
5863     assert( mit->type.prefix.empty() && mit->type.postfix.empty() );
5864     initializer = argumentName + ".size()";
5865     if ( arrayIt->len.front() == "codeSize / 4" )
5866     {
5867       initializer += " * 4";
5868     }
5869     if ( ( arrayIt->type.type == "void" ) &&
5870          ( std::count_if( arrayIt->type.postfix.begin(), arrayIt->type.postfix.end(), []( char c ) { return c == '*'; } ) < 2 ) )
5871     {
5872       initializer += " * sizeof(T)";
5873     }
5874   }
5875   if ( mit->type.type != "size_t" )
5876   {
5877     initializer = "static_cast<" + mit->type.type + ">( " + initializer + " )";
5878   }
5879   return initializer;
5880 }
5881 
generateName(TypeInfo const & typeInfo) const5882 std::string VulkanHppGenerator::generateName( TypeInfo const & typeInfo ) const
5883 {
5884   std::string name = stripPrefix( typeInfo.type, "Vk" );
5885   assert( typeInfo.prefix.find( '*' ) == std::string::npos );
5886   if ( typeInfo.postfix.find( '*' ) != std::string::npos )
5887   {
5888     assert( typeInfo.postfix.find_first_of( '*' ) == typeInfo.postfix.find_last_of( '*' ) );
5889     name = "p" + name;
5890   }
5891   else
5892   {
5893     name = startLowerCase( name );
5894   }
5895   return name;
5896 }
5897 
generateNoExcept(std::vector<std::string> const & errorCodes,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool vectorSizeCheck,bool raii) const5898 std::string VulkanHppGenerator::generateNoExcept( std::vector<std::string> const &          errorCodes,
5899                                                   std::vector<size_t> const &               returnParams,
5900                                                   std::map<size_t, VectorParamData> const & vectorParams,
5901                                                   CommandFlavourFlags                       flavourFlags,
5902                                                   bool                                      vectorSizeCheck,
5903                                                   bool                                      raii ) const
5904 {
5905   // noexcept is only possible with no error codes, and the return param (if any) is not a vector param (unless it's the singular version)
5906   return ( errorCodes.empty() &&
5907            ( ( flavourFlags & CommandFlavourFlagBits::singular ) || returnParams.empty() ||
5908              ( std::find_if( returnParams.begin(),
5909                              returnParams.end(),
5910                              [&vectorParams]( size_t rp ) { return vectorParams.find( rp ) != vectorParams.end(); } ) == returnParams.end() ) ) )
5911          ? ( vectorSizeCheck ? ( raii ? "" : " VULKAN_HPP_NOEXCEPT_WHEN_NO_EXCEPTIONS" ) : " VULKAN_HPP_NOEXCEPT" )
5912          : "";
5913 }
5914 
generateObjectDeleter(std::string const & commandName,CommandData const & commandData,size_t initialSkipCount,size_t returnParam) const5915 std::string VulkanHppGenerator::generateObjectDeleter( std::string const & commandName,
5916                                                        CommandData const & commandData,
5917                                                        size_t              initialSkipCount,
5918                                                        size_t              returnParam ) const
5919 {
5920   std::string objectDeleter, allocator;
5921   if ( ( commandName.find( "Acquire" ) != std::string::npos ) || ( commandName.find( "Get" ) != std::string::npos ) )
5922   {
5923     if ( ( commandName == "vkAcquirePerformanceConfigurationINTEL" ) || ( commandName == "vkGetRandROutputDisplayEXT" ) ||
5924          ( commandName == "vkGetWinrtDisplayNV" ) || ( commandName == "vkGetDrmDisplayEXT" ) )
5925     {
5926       objectDeleter = "ObjectRelease";
5927     }
5928     else
5929     {
5930       throw std::runtime_error( "Found " + commandName + " which requires special handling for the object deleter" );
5931     }
5932   }
5933   else if ( commandName.find( "Allocate" ) != std::string::npos )
5934   {
5935     objectDeleter = "ObjectFree";
5936     allocator     = "allocator, ";
5937   }
5938   else
5939   {
5940     assert( ( commandName.find( "Create" ) != std::string::npos ) || ( commandName.find( "Register" ) != std::string::npos ) );
5941     objectDeleter = "ObjectDestroy";
5942     allocator     = "allocator, ";
5943   }
5944   std::string className  = initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "";
5945   std::string parentName = ( className.empty() || ( commandData.params[returnParam].type.type == "VkDevice" ) ) ? "NoParent" : className;
5946   return objectDeleter + "<" + parentName + ", Dispatch>( " + ( ( parentName == "NoParent" ) ? "" : "*this, " ) + allocator + "d )";
5947 }
5948 
generateProtection(std::string const & protect) const5949 std::pair<std::string, std::string> VulkanHppGenerator::generateProtection( std::string const & protect ) const
5950 {
5951   return protect.empty() ? std::make_pair( "", "" ) : std::make_pair( "#if defined( " + protect + " )\n", "#endif /*" + protect + "*/\n" );
5952 }
5953 
generateRAIICommandDefinitions() const5954 std::string VulkanHppGenerator::generateRAIICommandDefinitions() const
5955 {
5956   const std::string commandDefinitionsTemplate = R"(
5957   //===========================
5958   //=== COMMAND Definitions ===
5959   //===========================
5960 
5961 ${commandDefinitions}
5962 )";
5963 
5964   std::string           commandDefinitions;
5965   std::set<std::string> listedCommands;  // some commands are listed with more than one extension!
5966   for ( auto const & feature : m_features )
5967   {
5968     commandDefinitions += generateRAIICommandDefinitions( feature.second.requireData, listedCommands, feature.first );
5969   }
5970   for ( auto const & extIt : m_extensionsByNumber )
5971   {
5972     commandDefinitions += generateRAIICommandDefinitions( extIt.second->second.requireData, listedCommands, extIt.second->first );
5973   }
5974 
5975   return replaceWithMap( commandDefinitionsTemplate, { { "commandDefinitions", commandDefinitions } } );
5976 }
5977 
generateRAIICommandDefinitions(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title) const5978 std::string VulkanHppGenerator::generateRAIICommandDefinitions( std::vector<RequireData> const & requireData,
5979                                                                 std::set<std::string> &          listedCommands,
5980                                                                 std::string const &              title ) const
5981 {
5982   std::string str;
5983   for ( auto const & require : requireData )
5984   {
5985     for ( auto const & command : require.commands )
5986     {
5987       if ( listedCommands.insert( command ).second )
5988       {
5989         str += generateRAIIHandleCommand( command, determineInitialSkipCount( command ), true );
5990       }
5991     }
5992   }
5993   return addTitleAndProtection( title, str );
5994 }
5995 
generateRAIIDispatchers() const5996 std::string VulkanHppGenerator::generateRAIIDispatchers() const
5997 {
5998   std::string contextInitializers, contextMembers, deviceAssignments, deviceMembers, instanceAssignments, instanceMembers;
5999 
6000   std::set<std::string> listedCommands;
6001   for ( auto const & feature : m_features )
6002   {
6003     appendRAIIDispatcherCommands( feature.second.requireData,
6004                                   listedCommands,
6005                                   feature.first,
6006                                   contextInitializers,
6007                                   contextMembers,
6008                                   deviceAssignments,
6009                                   deviceMembers,
6010                                   instanceAssignments,
6011                                   instanceMembers );
6012   }
6013   for ( auto const & extension : m_extensions )
6014   {
6015     appendRAIIDispatcherCommands( extension.second.requireData,
6016                                   listedCommands,
6017                                   extension.first,
6018                                   contextInitializers,
6019                                   contextMembers,
6020                                   deviceAssignments,
6021                                   deviceMembers,
6022                                   instanceAssignments,
6023                                   instanceMembers );
6024   }
6025 
6026   std::string contextDispatcherTemplate = R"(
6027     class ContextDispatcher : public DispatchLoaderBase
6028     {
6029     public:
6030       ContextDispatcher( PFN_vkGetInstanceProcAddr getProcAddr )
6031         : vkGetInstanceProcAddr( getProcAddr )${contextInitializers}
6032       {}
6033 
6034     public:
6035       PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = 0;
6036 ${contextMembers}
6037     };
6038 )";
6039 
6040   std::string str = replaceWithMap( contextDispatcherTemplate, { { "contextInitializers", contextInitializers }, { "contextMembers", contextMembers } } );
6041 
6042   std::string instanceDispatcherTemplate = R"(
6043     class InstanceDispatcher : public DispatchLoaderBase
6044     {
6045     public:
6046       InstanceDispatcher( PFN_vkGetInstanceProcAddr getProcAddr, VkInstance instance )
6047         : vkGetInstanceProcAddr( getProcAddr )
6048       {
6049 ${instanceAssignments}
6050         vkGetDeviceProcAddr =
6051           PFN_vkGetDeviceProcAddr( vkGetInstanceProcAddr( instance, "vkGetDeviceProcAddr" ) );
6052       }
6053 
6054     public:
6055 ${instanceMembers}
6056       PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = 0;
6057     };
6058 )";
6059 
6060   str += replaceWithMap( instanceDispatcherTemplate, { { "instanceAssignments", instanceAssignments }, { "instanceMembers", instanceMembers } } );
6061 
6062   std::string deviceDispatcherTemplate = R"(
6063     class DeviceDispatcher : public DispatchLoaderBase
6064     {
6065     public:
6066       DeviceDispatcher( PFN_vkGetDeviceProcAddr getProcAddr, VkDevice device ) : vkGetDeviceProcAddr( getProcAddr )
6067       {
6068 ${deviceAssignments}
6069       }
6070 
6071     public:
6072 ${deviceMembers}
6073     };
6074 )";
6075 
6076   str += replaceWithMap( deviceDispatcherTemplate, { { "deviceAssignments", deviceAssignments }, { "deviceMembers", deviceMembers } } );
6077   return str;
6078 }
6079 
generateRAIIHandle(std::pair<std::string,HandleData> const & handle,std::set<std::string> & listedHandles,std::set<std::string> const & specialFunctions) const6080 std::string VulkanHppGenerator::generateRAIIHandle( std::pair<std::string, HandleData> const & handle,
6081                                                     std::set<std::string> &                    listedHandles,
6082                                                     std::set<std::string> const &              specialFunctions ) const
6083 {
6084   std::string str;
6085   if ( listedHandles.find( handle.first ) == listedHandles.end() )
6086   {
6087     rescheduleRAIIHandle( str, handle, listedHandles, specialFunctions );
6088 
6089     auto [enter, leave]    = generateProtection( handle.second.alias.empty() ? getProtectFromType( handle.first ) : "" );
6090     std::string handleType = stripPrefix( handle.first, "Vk" );
6091     std::string handleName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
6092 
6093     auto [singularStaticCreates, arrayStaticCreates] = generateRAIIHandleStaticCreates( handle );
6094     auto [singularConstructors, arrayConstructors] = generateRAIIHandleConstructors( handle );
6095 
6096     auto [clearMembers, getConstructorSuccessCode, memberVariables, moveConstructorInitializerList, moveAssignmentInstructions, swapMembers, releaseMembers] =
6097       generateRAIIHandleDetails( handle );
6098 
6099     std::string declarations = generateRAIIHandleCommandDeclarations( handle, specialFunctions );
6100 
6101     assert( !handle.second.objTypeEnum.empty() );
6102     auto enumIt = m_enums.find( "VkObjectType" );
6103     assert( enumIt != m_enums.end() );
6104     auto valueIt = std::find_if(
6105       enumIt->second.values.begin(), enumIt->second.values.end(), [&handle]( EnumValueData const & evd ) { return evd.name == handle.second.objTypeEnum; } );
6106     assert( valueIt != enumIt->second.values.end() );
6107     std::string objTypeEnum = generateEnumValueName( enumIt->first, valueIt->name, false, m_tags );
6108 
6109     enumIt = m_enums.find( "VkDebugReportObjectTypeEXT" );
6110     assert( enumIt != m_enums.end() );
6111     std::string valueName = handle.second.objTypeEnum;
6112     valueName             = valueName.replace( 3, 0, "DEBUG_REPORT_" ) + "_EXT";
6113     valueIt =
6114       std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&valueName]( EnumValueData const & evd ) { return valueName == evd.name; } );
6115     std::string debugReportObjectType =
6116       ( valueIt != enumIt->second.values.end() ) ? generateEnumValueName( enumIt->first, valueIt->name, false, m_tags ) : "eUnknown";
6117 
6118     std::string dispatcherType = ( ( handle.first == "VkDevice" ) || ( handle.second.constructorIts.front()->second.params.front().type.type == "VkDevice" ) )
6119                                  ? "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher"
6120                                  : "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher";
6121 
6122     std::string getParent;
6123     if ( ( handle.first != "VkInstance" ) && ( handle.first != "VkDevice" ) && ( handle.second.destructorIt != m_commands.end() ) )
6124     {
6125       assert( !handle.second.destructorIt->second.params.empty() );
6126       std::string parentType = stripPrefix( handle.second.destructorIt->second.params.front().type.type, "Vk" );
6127       getParent              = "    VULKAN_HPP_NAMESPACE::" + parentType + " get" + parentType + "() const\n";
6128       getParent += "    {\n";
6129       getParent += "      return m_" + handle.second.destructorIt->second.params.front().name + ";\n";
6130       getParent += "    }\n";
6131     }
6132 
6133     std::string assignmentOperator, copyConstructor;
6134     if ( handle.second.destructorIt == m_commands.end() )
6135     {
6136       // allow copy constructor and assignment operator for classes without destructor
6137       std::string const copyConstructorTemplate =
6138         R"(      ${handleType}( ${handleType} const & rhs ) : m_${handleName}( rhs.m_${handleName} ), m_dispatcher( rhs.m_dispatcher ) {})";
6139       copyConstructor += replaceWithMap( copyConstructorTemplate, { { "handleName", handleName }, { "handleType", handleType } } );
6140 
6141       std::string assignmentOperatorTemplate = R"(      ${handleType} & operator=( ${handleType} const & rhs )
6142       {
6143         m_${handleName} = rhs.m_${handleName};
6144         m_dispatcher    = rhs.m_dispatcher;
6145         return *this;
6146       })";
6147       assignmentOperator += replaceWithMap( assignmentOperatorTemplate, { { "handleName", handleName }, { "handleType", handleType } } );
6148     }
6149     else
6150     {
6151       std::string const copyConstructorTemplate = R"(      ${handleType}( ${handleType} const & ) = delete;)";
6152       copyConstructor += replaceWithMap( copyConstructorTemplate, { { "handleType", handleType } } );
6153 
6154       std::string const assignmentOperatorTemplate = R"(      ${handleType} & operator=( ${handleType} const & ) = delete;)";
6155       assignmentOperator += replaceWithMap( assignmentOperatorTemplate, { { "handleType", handleType } } );
6156     }
6157 
6158     const std::string handleTemplate = R"(
6159 ${enter}  class ${handleType}
6160   {
6161   public:
6162     using CType = Vk${handleType};
6163 
6164     static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::ObjectType objectType = VULKAN_HPP_NAMESPACE::ObjectType::${objTypeEnum};
6165     static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT debugReportObjectType = VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT::${debugReportObjectType};
6166 
6167   public:
6168 ${singularStaticCreates}
6169 ${singularConstructors}
6170 
6171     ${handleType}( std::nullptr_t ) {}
6172 
6173     ~${handleType}()
6174     {
6175       clear();
6176     }
6177 
6178     ${handleType}() = delete;
6179 ${copyConstructor}
6180     ${handleType}( ${handleType} && rhs ) VULKAN_HPP_NOEXCEPT
6181       : ${moveConstructorInitializerList}
6182     {}
6183 ${assignmentOperator}
6184     ${handleType} & operator=( ${handleType} && rhs ) VULKAN_HPP_NOEXCEPT
6185     {
6186       if ( this != &rhs )
6187       {
6188 ${moveAssignmentInstructions}
6189       }
6190       return *this;
6191     }
6192 
6193     VULKAN_HPP_NAMESPACE::${handleType} const & operator*() const VULKAN_HPP_NOEXCEPT
6194     {
6195       return m_${handleName};
6196     }
6197 
6198     void clear() VULKAN_HPP_NOEXCEPT
6199     {
6200 ${clearMembers}
6201     }
6202 
6203     VULKAN_HPP_NAMESPACE::${handleType} release()
6204     {
6205 ${releaseMembers}
6206     }
6207 
6208 ${getConstructorSuccessCode}
6209 ${getParent}
6210     ${dispatcherType} const * getDispatcher() const
6211     {
6212       VULKAN_HPP_ASSERT( m_dispatcher->getVkHeaderVersion() == VK_HEADER_VERSION );
6213       return ${getDispatcherReturn}m_dispatcher;
6214     }
6215 
6216     void swap( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType} & rhs ) VULKAN_HPP_NOEXCEPT
6217     {
6218 ${swapMembers}
6219     }
6220 
6221 ${memberFunctionsDeclarations}
6222 
6223   private:
6224 
6225     ${memberVariables}
6226   };
6227 ${leave})";
6228 
6229     str += replaceWithMap( handleTemplate,
6230                            { { "assignmentOperator", assignmentOperator },
6231                              { "clearMembers", clearMembers },
6232                              { "copyConstructor", copyConstructor },
6233                              { "debugReportObjectType", debugReportObjectType },
6234                              { "dispatcherType", dispatcherType },
6235                              { "enter", enter },
6236                              { "getConstructorSuccessCode", getConstructorSuccessCode },
6237                              { "getDispatcherReturn", ( handleType == "Device" ) || ( handleType == "Instance" ) ? "&*" : "" },
6238                              { "getParent", getParent },
6239                              { "handleName", handleName },
6240                              { "handleType", handleType },
6241                              { "leave", leave },
6242                              { "memberFunctionsDeclarations", declarations },
6243                              { "memberVariables", memberVariables },
6244                              { "moveAssignmentInstructions", moveAssignmentInstructions },
6245                              { "moveConstructorInitializerList", moveConstructorInitializerList },
6246                              { "objTypeEnum", objTypeEnum },
6247                              { "releaseMembers", releaseMembers },
6248                              { "singularConstructors", singularConstructors },
6249                              { "singularStaticCreates", singularStaticCreates },
6250                              { "swapMembers", swapMembers } } );
6251 
6252     if ( !arrayConstructors.empty() )
6253     {
6254       // it's a handle class with a friendly handles class
6255       const std::string handlesTemplate = R"(
6256 ${enter}  class ${handleType}s : public std::vector<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}>
6257   {
6258   public:
6259     ${arrayStaticCreates}
6260     ${arrayConstructors}
6261     ${handleType}s( std::nullptr_t ) {}
6262 
6263     ${handleType}s() = delete;
6264     ${handleType}s( ${handleType}s const & ) = delete;
6265     ${handleType}s( ${handleType}s && rhs ) = default;
6266     ${handleType}s & operator=( ${handleType}s const & ) = delete;
6267     ${handleType}s & operator=( ${handleType}s && rhs ) = default;
6268   };
6269 ${leave}
6270 )";
6271 
6272       str += replaceWithMap( handlesTemplate,
6273                              { { "arrayConstructors", arrayConstructors },
6274                                { "arrayStaticCreates", arrayStaticCreates },
6275                                { "enter", enter },
6276                                { "handleType", handleType },
6277                                { "leave", leave } } );
6278     }
6279   }
6280   return str;
6281 }
6282 
generateRAIIHandleCommand(std::string const & command,size_t initialSkipCount,bool definition) const6283 std::string VulkanHppGenerator::generateRAIIHandleCommand( std::string const & command, size_t initialSkipCount, bool definition ) const
6284 {
6285   std::string str;
6286   if ( m_RAIISpecialFunctions.find( command ) == m_RAIISpecialFunctions.end() )
6287   {
6288     auto commandIt = m_commands.find( command );
6289     assert( commandIt != m_commands.end() );
6290 
6291     if ( commandIt->second.returnType == "VkResult" )
6292     {
6293       str = generateRAIIHandleCommandResult( commandIt, initialSkipCount, definition );
6294     }
6295     else if ( commandIt->second.returnType == "void" )
6296     {
6297       str = generateRAIIHandleCommandVoid( commandIt, initialSkipCount, definition );
6298     }
6299     else
6300     {
6301       str = generateRAIIHandleCommandValue( commandIt, initialSkipCount, definition );
6302     }
6303 
6304     if ( str.empty() )
6305     {
6306       throw std::runtime_error( "Never encountered a command like <" + command + "> !" );
6307     }
6308   }
6309   return str;
6310 }
6311 
generateRAIIHandleCommandDeclarations(std::pair<std::string,HandleData> const & handle,std::set<std::string> const & specialFunctions) const6312 std::string VulkanHppGenerator::generateRAIIHandleCommandDeclarations( std::pair<std::string, HandleData> const & handle,
6313                                                                        std::set<std::string> const &              specialFunctions ) const
6314 {
6315   std::string           functionDeclarations;
6316   std::set<std::string> listedCommands;  // some commands are listed with more than one extension !
6317   for ( auto const & feature : m_features )
6318   {
6319     std::vector<std::string> firstLevelCommands, secondLevelCommands;
6320 
6321     for ( auto const & require : feature.second.requireData )
6322     {
6323       for ( auto const & command : require.commands )
6324       {
6325         if ( specialFunctions.find( command ) == specialFunctions.end() )
6326         {
6327           if ( handle.second.commands.find( command ) != handle.second.commands.end() )
6328           {
6329             assert( listedCommands.find( command ) == listedCommands.end() );
6330             listedCommands.insert( command );
6331             firstLevelCommands.push_back( command );
6332           }
6333           else if ( handle.second.secondLevelCommands.find( command ) != handle.second.secondLevelCommands.end() )
6334           {
6335             assert( listedCommands.find( command ) == listedCommands.end() );
6336             listedCommands.insert( command );
6337             assert( !handle.first.empty() );
6338             secondLevelCommands.push_back( command );
6339           }
6340         }
6341       }
6342     }
6343     if ( !firstLevelCommands.empty() || !secondLevelCommands.empty() )
6344     {
6345       functionDeclarations += "\n  //=== " + feature.first + " ===\n";
6346       for ( auto const & command : firstLevelCommands )
6347       {
6348         functionDeclarations += generateRAIIHandleCommand( command, handle.first.empty() ? 0 : 1, false );
6349       }
6350       for ( auto const & command : secondLevelCommands )
6351       {
6352         assert( !handle.first.empty() );
6353         functionDeclarations += generateRAIIHandleCommand( command, 2, false );
6354       }
6355     }
6356   }
6357 
6358   for ( auto const & extIt : m_extensionsByNumber )
6359   {
6360     std::vector<std::string> firstLevelCommands, secondLevelCommands;
6361     for ( auto & req : extIt.second->second.requireData )
6362     {
6363       for ( auto const & command : req.commands )
6364       {
6365         if ( ( specialFunctions.find( command ) == specialFunctions.end() ) && ( listedCommands.find( command ) == listedCommands.end() ) )
6366         {
6367           if ( handle.second.commands.find( command ) != handle.second.commands.end() )
6368           {
6369             listedCommands.insert( command );
6370             firstLevelCommands.push_back( command );
6371           }
6372           else if ( handle.second.secondLevelCommands.find( command ) != handle.second.secondLevelCommands.end() )
6373           {
6374             listedCommands.insert( command );
6375             secondLevelCommands.push_back( command );
6376           }
6377         }
6378       }
6379     }
6380     if ( !firstLevelCommands.empty() || !secondLevelCommands.empty() )
6381     {
6382       std::string enter, leave;
6383       if ( extIt.second->first != m_types.find( handle.first )->second.referencedIn )
6384       {
6385         std::tie( enter, leave ) = generateProtection( getProtectFromTitle( extIt.second->first ) );
6386       }
6387       functionDeclarations += "\n" + enter + "  //=== " + extIt.second->first + " ===\n";
6388       for ( auto const & command : firstLevelCommands )
6389       {
6390         functionDeclarations += generateRAIIHandleCommand( command, handle.first.empty() ? 0 : 1, false );
6391       }
6392       for ( auto const & command : secondLevelCommands )
6393       {
6394         assert( !handle.first.empty() );
6395         functionDeclarations += generateRAIIHandleCommand( command, 2, false );
6396       }
6397       functionDeclarations += leave;
6398     }
6399   }
6400   return functionDeclarations;
6401 }
6402 
generateRAIIHandleCommandEnhanced(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,bool definition,CommandFlavourFlags flavourFlags) const6403 std::string VulkanHppGenerator::generateRAIIHandleCommandEnhanced( std::map<std::string, CommandData>::const_iterator commandIt,
6404                                                                    size_t                                             initialSkipCount,
6405                                                                    std::vector<size_t> const &                        returnParams,
6406                                                                    std::map<size_t, VectorParamData> const &          vectorParams,
6407                                                                    bool                                               definition,
6408                                                                    CommandFlavourFlags                                flavourFlags ) const
6409 {
6410   bool singular = flavourFlags & CommandFlavourFlagBits::singular;
6411 
6412   std::set<size_t> skippedParams  = determineSkippedParams( commandIt->second.params, initialSkipCount, vectorParams, returnParams, singular );
6413   std::set<size_t> singularParams = singular ? determineSingularParams( returnParams[0], vectorParams ) : std::set<size_t>();
6414   // special handling for vkGetMemoryHostPointerPropertiesEXT: here, we really need to stick with the const void * parameter !
6415   std::set<size_t> templatedParams =
6416     ( commandIt->first == "vkGetMemoryHostPointerPropertiesEXT" ) ? std::set<size_t>() : determineVoidPointerParams( commandIt->second.params );
6417 
6418   bool                     enumerating = determineEnumeration( vectorParams, returnParams );
6419   std::vector<std::string> dataTypes   = determineDataTypes( commandIt->second.params, vectorParams, returnParams, templatedParams );
6420   std::string              dataType    = combineDataTypes( vectorParams, returnParams, enumerating, dataTypes, flavourFlags, true );
6421 
6422   std::string argumentTemplates = generateArgumentTemplates( commandIt->second.params, returnParams, vectorParams, templatedParams, flavourFlags, true );
6423   std::string argumentList      = generateArgumentListEnhanced(
6424     commandIt->second.params, returnParams, vectorParams, skippedParams, singularParams, templatedParams, definition, flavourFlags, false );
6425   std::string commandName = generateCommandName( commandIt->first, commandIt->second.params, initialSkipCount, m_tags, flavourFlags );
6426   std::string nodiscard =
6427     generateNoDiscard( !returnParams.empty() || ( ( commandIt->second.returnType != "VkResult" ) && ( commandIt->second.returnType != "void" ) ),
6428                        1 < commandIt->second.successCodes.size(),
6429                        false );
6430   std::pair<bool, std::map<size_t, std::vector<size_t>>> vectorSizeCheck =
6431     needsVectorSizeCheck( commandIt->second.params, vectorParams, returnParams, singularParams );
6432   std::string noexceptString = generateNoExcept( commandIt->second.errorCodes, returnParams, vectorParams, flavourFlags, vectorSizeCheck.first, true );
6433   std::string returnType     = generateReturnType( commandIt->second, returnParams, vectorParams, flavourFlags, true, dataType );
6434 
6435   std::string debugHelper = "";
6436   #ifdef DEBUG_GENERATOR
6437   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
6438   #endif
6439 
6440   if ( definition )
6441   {
6442     std::string const definitionTemplate =
6443       R"(
6444   ${argumentTemplates}
6445   ${nodiscard} VULKAN_HPP_INLINE ${returnType} ${className}::${commandName}( ${argumentList} ) const ${noexcept} ${debugHelper}
6446   {
6447 ${functionPointerCheck}
6448 ${vectorSizeCheck}
6449     ${dataSizeChecks}
6450     ${dataDeclarations}
6451     ${callSequence}
6452     ${resultCheck}
6453     ${dataPreparation}
6454     ${returnStatement}
6455   }
6456 )";
6457 
6458     std::string callSequence = generateCallSequence(
6459       commandIt->first, commandIt->second, returnParams, vectorParams, initialSkipCount, singularParams, templatedParams, flavourFlags, true );
6460     std::string className        = initialSkipCount ? stripPrefix( commandIt->second.params[initialSkipCount - 1].type.type, "Vk" ) : "Context";
6461     std::string returnVariable   = generateReturnVariable( commandIt->second, returnParams, vectorParams, flavourFlags );
6462     std::string dataDeclarations = generateDataDeclarations(
6463       commandIt->second, returnParams, vectorParams, templatedParams, flavourFlags, true, dataTypes, dataType, returnType, returnVariable );
6464     std::string dataPreparation =
6465       generateDataPreparation( commandIt->second, initialSkipCount, returnParams, vectorParams, templatedParams, flavourFlags, enumerating );
6466     std::string dataSizeChecks  = generateDataSizeChecks( commandIt->second, returnParams, dataTypes, vectorParams, templatedParams, singular );
6467     std::string resultCheck     = generateResultCheck( commandIt->second, className, "::", commandName, enumerating );
6468     std::string returnStatement = generateReturnStatement( commandIt->first,
6469                                                            commandIt->second,
6470                                                            returnVariable,
6471                                                            returnType,
6472                                                            dataType,
6473                                                            initialSkipCount,
6474                                                            returnParams.empty() ? INVALID_INDEX : returnParams[0],
6475                                                            flavourFlags,
6476                                                            enumerating,
6477                                                            true );
6478     std::string vectorSizeCheckString =
6479       vectorSizeCheck.first ? generateRAIIHandleVectorSizeCheck( commandIt->first, commandIt->second, initialSkipCount, vectorSizeCheck.second, skippedParams )
6480                             : "";
6481 
6482     return replaceWithMap( definitionTemplate,
6483                            { { "argumentList", argumentList },
6484                              { "argumentTemplates", argumentTemplates },
6485                              { "callSequence", callSequence },
6486                              { "className", className },
6487                              { "commandName", commandName },
6488                              { "dataDeclarations", dataDeclarations },
6489                              { "dataPreparation", dataPreparation },
6490                              { "dataSizeChecks", dataSizeChecks },
6491                              { "debugHelper", debugHelper },
6492                              { "functionPointerCheck", generateFunctionPointerCheck( commandIt->first, commandIt->second.referencedIn ) },
6493                              { "nodiscard", nodiscard },
6494                              { "noexcept", noexceptString },
6495                              { "resultCheck", resultCheck },
6496                              { "returnStatement", returnStatement },
6497                              { "returnType", returnType },
6498                              { "vectorSizeCheck", vectorSizeCheckString } } );
6499   }
6500   else
6501   {
6502     std::string const declarationTemplate =
6503       R"(
6504     ${argumentTemplates}
6505     ${nodiscard} ${returnType} ${commandName}( ${argumentList} ) const ${noexcept};
6506 )";
6507 
6508     return replaceWithMap( declarationTemplate,
6509                            { { "argumentList", argumentList },
6510                              { "argumentTemplates", argumentTemplates },
6511                              { "commandName", commandName },
6512                              { "nodiscard", nodiscard },
6513                              { "noexcept", noexceptString },
6514                              { "returnType", returnType } } );
6515   }
6516 }
6517 
generateRAIIHandleCommandFactory(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,bool definition,CommandFlavourFlags flavourFlags) const6518 std::string VulkanHppGenerator::generateRAIIHandleCommandFactory( std::map<std::string, CommandData>::const_iterator commandIt,
6519                                                                   size_t                                             initialSkipCount,
6520                                                                   std::vector<size_t> const &                        returnParams,
6521                                                                   std::map<size_t, VectorParamData> const &          vectorParams,
6522                                                                   bool                                               definition,
6523                                                                   CommandFlavourFlags                                flavourFlags ) const
6524 {
6525   bool singular = flavourFlags & CommandFlavourFlagBits::singular;
6526 
6527   assert( isHandleType( commandIt->second.params[returnParams.back()].type.type ) );
6528   assert( ( returnParams.size() == 1 ) ||
6529           ( ( returnParams.size() == 2 ) && ( vectorParams.size() == 1 ) && ( returnParams[0] == vectorParams.begin()->second.lenParam ) &&
6530             ( returnParams[1] == vectorParams.begin()->first ) ) );
6531 
6532   std::set<size_t> skippedParams  = determineSkippedParams( commandIt->second.params, initialSkipCount, vectorParams, returnParams, singular );
6533   std::set<size_t> singularParams = singular ? determineSingularParams( returnParams.back(), vectorParams ) : std::set<size_t>();
6534   std::string      argumentList   = generateRAIIHandleCommandFactoryArgumentList( commandIt->second.params, skippedParams, definition, singular );
6535   std::string      commandName    = generateCommandName( commandIt->first, commandIt->second.params, initialSkipCount, m_tags, flavourFlags );
6536   std::string      handleType     = stripPostfix( commandIt->second.params[returnParams.back()].type.compose( "VULKAN_HPP_RAII_NAMESPACE" ), " *" );
6537   std::string      returnType     = handleType;
6538   if ( ( vectorParams.find( returnParams.back() ) != vectorParams.end() ) && !singular )
6539   {
6540     returnType = "std::vector<" + handleType + ">";
6541     handleType += "s";
6542   }
6543 
6544   std::string debugHelper = "";
6545   #ifdef DEBUG_GENERATOR
6546   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
6547   #endif
6548 
6549   if ( definition )
6550   {
6551     std::string callArguments = generateCallArgumentsRAIIFactory( commandIt->second.params, initialSkipCount, skippedParams, singularParams );
6552     std::string className     = initialSkipCount ? stripPrefix( commandIt->second.params[initialSkipCount - 1].type.type, "Vk" ) : "Context";
6553 
6554     std::string const definitionTemplate =
6555       R"(
6556 #ifndef VULKAN_HPP_NO_EXCEPTIONS
6557   VULKAN_HPP_NODISCARD VULKAN_HPP_INLINE ${returnType} ${className}::${commandName}( ${argumentList} ) const ${debugHelper}
6558   {
6559     return ${handleType}( ${callArguments} );
6560   }
6561 #endif
6562 )";
6563 
6564     return replaceWithMap( definitionTemplate,
6565                            { { "argumentList", argumentList },
6566                              { "callArguments", callArguments },
6567                              { "className", className },
6568                              { "commandName", commandName },
6569                              { "debugHelper", debugHelper },
6570                              { "handleType", handleType },
6571                              { "returnType", returnType } } );
6572   }
6573   else
6574   {
6575     std::string const declarationTemplate =
6576       R"(
6577 #ifndef VULKAN_HPP_NO_EXCEPTIONS
6578   VULKAN_HPP_NODISCARD ${returnType} ${commandName}( ${argumentList} ) const; ${debugHelper}
6579 #endif
6580 )";
6581 
6582     return replaceWithMap( declarationTemplate,
6583                            { { "argumentList", argumentList },
6584                            { "commandName", commandName },
6585                            { "debugHelper", debugHelper },
6586                            { "returnType", returnType } } );
6587   }
6588 }
6589 
generateRAIIHandleCommandFactoryArgumentList(std::vector<ParamData> const & params,std::set<size_t> const & skippedParams,bool definition,bool singular) const6590 std::string VulkanHppGenerator::generateRAIIHandleCommandFactoryArgumentList( std::vector<ParamData> const & params,
6591                                                                               std::set<size_t> const &       skippedParams,
6592                                                                               bool                           definition,
6593                                                                               bool                           singular ) const
6594 {
6595   std::string arguments;
6596   bool        encounteredArgument = false;
6597   for ( size_t i = 0; i < params.size(); ++i )
6598   {
6599     if ( skippedParams.find( i ) == skippedParams.end() )
6600     {
6601       if ( encounteredArgument )
6602       {
6603         arguments += ", ";
6604       }
6605       arguments += generateRAIIHandleConstructorArgument( params[i], definition, singular, false );
6606       encounteredArgument = true;
6607     }
6608   }
6609   return arguments;
6610 }
6611 
generateRAIIHandleCommandResult(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6612 std::string VulkanHppGenerator::generateRAIIHandleCommandResult( std::map<std::string, CommandData>::const_iterator commandIt,
6613                                                                  size_t                                             initialSkipCount,
6614                                                                  bool                                               definition ) const
6615 {
6616   assert( !commandIt->second.successCodes.empty() );
6617   if ( commandIt->second.successCodes.size() == 1 )
6618   {
6619     if ( commandIt->second.errorCodes.empty() )
6620     {
6621       return generateRAIIHandleCommandResultSingleSuccessNoErrors( commandIt, initialSkipCount, definition );
6622     }
6623     else
6624     {
6625       return generateRAIIHandleCommandResultSingleSuccessWithErrors( commandIt, initialSkipCount, definition );
6626     }
6627   }
6628   else
6629   {
6630     if ( commandIt->second.errorCodes.empty() )
6631     {
6632       return generateRAIIHandleCommandResultMultiSuccessNoErrors( commandIt, initialSkipCount, definition );
6633     }
6634     else
6635     {
6636       return generateRAIIHandleCommandResultMultiSuccessWithErrors( commandIt, initialSkipCount, definition );
6637     }
6638   }
6639 }
6640 
generateRAIIHandleCommandResultMultiSuccessNoErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6641 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessNoErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6642                                                                                      size_t                                             initialSkipCount,
6643                                                                                      bool                                               definition ) const
6644 {
6645   std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6646   switch ( returnParams.size() )
6647   {
6648     case 0:
6649       return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, determineVectorParams( commandIt->second.params ), definition );
6650     case 2: return generateRAIIHandleCommandResultMultiSuccessNoErrors2Return( commandIt, initialSkipCount, definition, returnParams );
6651   }
6652   return "";
6653 }
6654 
generateRAIIHandleCommandResultMultiSuccessNoErrors2Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const6655 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessNoErrors2Return( std::map<std::string, CommandData>::const_iterator commandIt,
6656                                                                                             size_t                                             initialSkipCount,
6657                                                                                             bool                                               definition,
6658                                                                                             std::vector<size_t> const & returnParams ) const
6659 {
6660   if ( ( commandIt->second.successCodes.size() == 2 ) && ( commandIt->second.successCodes[0] == "VK_SUCCESS" ) &&
6661        ( commandIt->second.successCodes[1] == "VK_INCOMPLETE" ) )
6662   {
6663     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6664     if ( vectorParams.size() == 1 )
6665     {
6666       if ( returnParams[0] == vectorParams.begin()->second.lenParam )
6667       {
6668         if ( returnParams[1] == vectorParams.begin()->first )
6669         {
6670           if ( ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" ) || ( commandIt->second.params[returnParams[0]].type.type == "size_t" ) )
6671           {
6672             if ( ( commandIt->second.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[1]].type.type ) &&
6673                  !isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6674             {
6675               return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6676             }
6677           }
6678         }
6679       }
6680     }
6681   }
6682   return "";
6683 }
6684 
generateRAIIHandleCommandResultMultiSuccessWithErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6685 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6686                                                                                        size_t                                             initialSkipCount,
6687                                                                                        bool                                               definition ) const
6688 {
6689   std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6690   switch ( returnParams.size() )
6691   {
6692     case 0:
6693       return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, determineVectorParams( commandIt->second.params ), definition );
6694       break;
6695     case 1: return generateRAIIHandleCommandResultMultiSuccessWithErrors1Return( commandIt, initialSkipCount, definition, returnParams[0] ); break;
6696     case 2: return generateRAIIHandleCommandResultMultiSuccessWithErrors2Return( commandIt, initialSkipCount, definition, returnParams ); break;
6697     case 3: return generateRAIIHandleCommandResultMultiSuccessWithErrors3Return( commandIt, initialSkipCount, definition, returnParams ); break;
6698   }
6699   return "";
6700 }
6701 
generateRAIIHandleCommandResultMultiSuccessWithErrors1Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6702 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors1Return( std::map<std::string, CommandData>::const_iterator commandIt,
6703                                                                                               size_t initialSkipCount,
6704                                                                                               bool   definition,
6705                                                                                               size_t returnParam ) const
6706 {
6707   if ( commandIt->second.params[returnParam].type.type == "void" )
6708   {
6709     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6710     if ( vectorParams.size() == 1 )
6711     {
6712       if ( returnParam == vectorParams.begin()->first )
6713       {
6714         if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "size_t" )
6715         {
6716           return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6717                  generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6718         }
6719       }
6720     }
6721   }
6722   else if ( isHandleType( commandIt->second.params[returnParam].type.type ) )
6723   {
6724     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6725     if ( vectorParams.size() == 2 )
6726     {
6727       if ( returnParam == std::next( vectorParams.begin() )->first )
6728       {
6729         if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
6730         {
6731           if ( isStructureChainAnchor( commandIt->second.params[vectorParams.begin()->first].type.type ) )
6732           {
6733             return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6734                    generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6735           }
6736         }
6737       }
6738     }
6739   }
6740   else
6741   {
6742     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6743     if ( vectorParams.empty() )
6744     {
6745       std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6746       if ( isStructureChainAnchor( commandIt->second.params[returnParam].type.type ) )
6747       {
6748         str += generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::chained );
6749       }
6750       return str;
6751     }
6752   }
6753   return "";
6754 }
6755 
generateRAIIHandleCommandResultMultiSuccessWithErrors2Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const6756 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors2Return( std::map<std::string, CommandData>::const_iterator commandIt,
6757                                                                                               size_t                      initialSkipCount,
6758                                                                                               bool                        definition,
6759                                                                                               std::vector<size_t> const & returnParams ) const
6760 {
6761   if ( ( commandIt->second.successCodes.size() == 2 ) && ( commandIt->second.successCodes[0] == "VK_SUCCESS" ) &&
6762        ( commandIt->second.successCodes[1] == "VK_INCOMPLETE" ) )
6763   {
6764     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6765     switch ( vectorParams.size() )
6766     {
6767       case 0:
6768         if ( ( commandIt->second.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[0]].type.type ) &&
6769              !isStructureChainAnchor( commandIt->second.params[returnParams[0]].type.type ) )
6770         {
6771           if ( ( commandIt->second.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[1]].type.type ) &&
6772                !isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6773           {
6774             return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6775           }
6776         }
6777         break;
6778       case 1:
6779         if ( returnParams[0] == vectorParams.begin()->second.lenParam )
6780         {
6781           if ( returnParams[1] == vectorParams.begin()->first )
6782           {
6783             if ( ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" ) || ( commandIt->second.params[returnParams[0]].type.type == "size_t" ) )
6784             {
6785               // needs some very special handling of "vkGetSwapchainImagesKHR" !!
6786               if ( isHandleType( commandIt->second.params[returnParams[1]].type.type ) && ( commandIt->first != "vkGetSwapchainImagesKHR" ) )
6787               {
6788                 return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6789               }
6790               else
6791               {
6792                 std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6793                 if ( isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6794                 {
6795                   str +=
6796                     generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::chained );
6797                 }
6798                 return str;
6799               }
6800             }
6801           }
6802         }
6803         break;
6804     }
6805   }
6806   return "";
6807 }
6808 
generateRAIIHandleCommandResultMultiSuccessWithErrors3Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const6809 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors3Return( std::map<std::string, CommandData>::const_iterator commandIt,
6810                                                                                               size_t                      initialSkipCount,
6811                                                                                               bool                        definition,
6812                                                                                               std::vector<size_t> const & returnParams ) const
6813 {
6814   if ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" )
6815   {
6816     if ( ( commandIt->second.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[1]].type.type ) &&
6817          !isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6818     {
6819       if ( ( commandIt->second.params[returnParams[2]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[2]].type.type ) &&
6820            !isStructureChainAnchor( commandIt->second.params[returnParams[2]].type.type ) )
6821       {
6822         std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6823         if ( vectorParams.size() == 2 )
6824         {
6825           if ( returnParams[0] == vectorParams.begin()->second.lenParam )
6826           {
6827             if ( returnParams[1] == vectorParams.begin()->first )
6828             {
6829               if ( returnParams[2] == std::next( vectorParams.begin() )->first )
6830               {
6831                 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
6832                 {
6833                   if ( ( commandIt->second.successCodes.size() == 2 ) && ( commandIt->second.successCodes[0] == "VK_SUCCESS" ) &&
6834                        ( commandIt->second.successCodes[1] == "VK_INCOMPLETE" ) )
6835                   {
6836                     return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6837                   }
6838                 }
6839               }
6840             }
6841           }
6842         }
6843       }
6844     }
6845   }
6846   return "";
6847 }
6848 
generateRAIIHandleCommandResultSingleSuccessNoErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6849 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessNoErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6850                                                                                       size_t                                             initialSkipCount,
6851                                                                                       bool                                               definition ) const
6852 {
6853   std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6854   if ( returnParams.size() < 2 )
6855   {
6856     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6857     return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6858   }
6859   return "";
6860 }
6861 
generateRAIIHandleCommandResultSingleSuccessWithErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6862 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6863                                                                                         size_t                                             initialSkipCount,
6864                                                                                         bool                                               definition ) const
6865 {
6866   std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6867   switch ( returnParams.size() )
6868   {
6869     case 0:
6870       return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, determineVectorParams( commandIt->second.params ), definition );
6871       break;
6872     case 1: return generateRAIIHandleCommandResultSingleSuccessWithErrors1Return( commandIt, initialSkipCount, definition, returnParams[0] ); break;
6873     case 2: return generateRAIIHandleCommandResultSingleSuccessWithErrors2Return( commandIt, initialSkipCount, definition, returnParams ); break;
6874   }
6875   return "";
6876 }
6877 
generateRAIIHandleCommandResultSingleSuccessWithErrors1Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6878 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1Return( std::map<std::string, CommandData>::const_iterator commandIt,
6879                                                                                                size_t initialSkipCount,
6880                                                                                                bool   definition,
6881                                                                                                size_t returnParam ) const
6882 {
6883   if ( commandIt->second.params[returnParam].type.type == "void" )
6884   {
6885     return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnVoid( commandIt, initialSkipCount, definition, returnParam );
6886   }
6887   else if ( isHandleType( commandIt->second.params[returnParam].type.type ) )
6888   {
6889     return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnHandle( commandIt, initialSkipCount, definition, returnParam );
6890   }
6891   else if ( isStructureChainAnchor( commandIt->second.params[returnParam].type.type ) )
6892   {
6893     return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnChain( commandIt, initialSkipCount, definition, returnParam );
6894   }
6895   else
6896   {
6897     return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue( commandIt, initialSkipCount, definition, returnParam );
6898   }
6899 }
6900 
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnChain(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6901 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnChain(
6902   std::map<std::string, CommandData>::const_iterator commandIt, size_t initialSkipCount, bool definition, size_t returnParam ) const
6903 {
6904   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6905   if ( vectorParams.empty() )
6906   {
6907     return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6908            generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::chained );
6909   }
6910   return "";
6911 }
6912 
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnHandle(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6913 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnHandle(
6914   std::map<std::string, CommandData>::const_iterator commandIt, size_t initialSkipCount, bool definition, size_t returnParam ) const
6915 {
6916   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6917   switch ( vectorParams.size() )
6918   {
6919     case 0: return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6920     case 1:
6921       if ( returnParam == vectorParams.begin()->first )
6922       {
6923         if ( m_structures.find( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type ) != m_structures.end() )
6924         {
6925           return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6926         }
6927       }
6928       break;
6929     case 2:
6930       if ( returnParam == std::next( vectorParams.begin() )->first )
6931       {
6932         if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
6933         {
6934           if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
6935           {
6936             if ( ( commandIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
6937                  !isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) )
6938             {
6939               return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6940                      generateRAIIHandleCommandFactory(
6941                        commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6942             }
6943           }
6944         }
6945       }
6946       break;
6947   }
6948   return "";
6949 }
6950 
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6951 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue(
6952   std::map<std::string, CommandData>::const_iterator commandIt, size_t initialSkipCount, bool definition, size_t returnParam ) const
6953 {
6954   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6955   switch ( vectorParams.size() )
6956   {
6957     case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6958     case 2:
6959       return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( commandIt, initialSkipCount, definition, returnParam, vectorParams );
6960   }
6961   return "";
6962 }
6963 
6964 std::string
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue2Vectors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const6965   VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( std::map<std::string, CommandData>::const_iterator commandIt,
6966                                                                                                   size_t                                    initialSkipCount,
6967                                                                                                   bool                                      definition,
6968                                                                                                   size_t                                    returnParam,
6969                                                                                                   std::map<size_t, VectorParamData> const & vectorParams ) const
6970 {
6971   if ( returnParam == std::next( vectorParams.begin() )->first )
6972   {
6973     if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
6974     {
6975       if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
6976       {
6977         if ( ( commandIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
6978              !isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) &&
6979              !isStructureChainAnchor( commandIt->second.params[vectorParams.begin()->first].type.type ) )
6980         {
6981           return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6982                  generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6983         }
6984       }
6985     }
6986   }
6987   return "";
6988 }
6989 
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnVoid(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6990 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnVoid( std::map<std::string, CommandData>::const_iterator commandIt,
6991                                                                                                    size_t initialSkipCount,
6992                                                                                                    bool   definition,
6993                                                                                                    size_t returnParam ) const
6994 {
6995   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6996   switch ( vectorParams.size() )
6997   {
6998     case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6999     case 1:
7000       if ( returnParam == vectorParams.begin()->first )
7001       {
7002         if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "size_t" )
7003         {
7004           return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
7005                  generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
7006         }
7007       }
7008       break;
7009     case 2:
7010       if ( returnParam == std::next( vectorParams.begin() )->first )
7011       {
7012         if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7013         {
7014           if ( isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) )
7015           {
7016             if ( commandIt->second.params[std::next( vectorParams.begin() )->second.lenParam].type.type == "size_t" )
7017             {
7018               return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
7019                      generateRAIIHandleCommandEnhanced(
7020                        commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
7021             }
7022           }
7023         }
7024       }
7025       break;
7026   }
7027   return "";
7028 }
7029 
generateRAIIHandleCommandResultSingleSuccessWithErrors2Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const7030 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors2Return( std::map<std::string, CommandData>::const_iterator commandIt,
7031                                                                                                size_t                      initialSkipCount,
7032                                                                                                bool                        definition,
7033                                                                                                std::vector<size_t> const & returnParams ) const
7034 {
7035   if ( commandIt->second.params[returnParams[0]].type.type == "uint64_t" )
7036   {
7037     if ( commandIt->second.params[returnParams[1]].type.type == "uint64_t" )
7038     {
7039       std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
7040       if ( vectorParams.size() == 2 )
7041       {
7042         if ( returnParams[0] == std::next( vectorParams.begin() )->first )
7043         {
7044           assert( returnParams[1] != std::next( vectorParams.begin() )->second.lenParam );
7045           if ( returnParams[1] != vectorParams.begin()->first )
7046           {
7047             assert( returnParams[1] != vectorParams.begin()->second.lenParam );
7048             if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
7049             {
7050               if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7051               {
7052                 if ( ( commandIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
7053                      !isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) &&
7054                      !isStructureChainAnchor( commandIt->second.params[vectorParams.begin()->first].type.type ) )
7055                 {
7056                   // two returns and two vectors! But one input vector, one output vector of the same size,
7057                   // and one output value
7058                   return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition ) +
7059                          generateRAIIHandleCommandEnhanced(
7060                            commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::singular );
7061                 }
7062               }
7063             }
7064           }
7065         }
7066       }
7067     }
7068   }
7069   return "";
7070 }
7071 
generateRAIIHandleCommandValue(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const7072 std::string VulkanHppGenerator::generateRAIIHandleCommandValue( std::map<std::string, CommandData>::const_iterator commandIt,
7073                                                                 size_t                                             initialSkipCount,
7074                                                                 bool                                               definition ) const
7075 {
7076   std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
7077   if ( returnParams.empty() )
7078   {
7079     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
7080     if ( vectorParams.size() <= 1 )
7081     {
7082       return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7083     }
7084   }
7085   return "";
7086 }
7087 
generateRAIIHandleCommandVoid(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const7088 std::string VulkanHppGenerator::generateRAIIHandleCommandVoid( std::map<std::string, CommandData>::const_iterator commandIt,
7089                                                                size_t                                             initialSkipCount,
7090                                                                bool                                               definition ) const
7091 {
7092   std::vector<size_t>               returnParams = determineReturnParams( commandIt->second.params );
7093   std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
7094   switch ( returnParams.size() )
7095   {
7096     case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7097     case 1:
7098       if ( commandIt->second.params[returnParams[0]].type.type == "void" )
7099       {
7100         if ( commandIt->second.params[returnParams[0]].type.postfix == "**" )
7101         {
7102           // get a pointer to something
7103           if ( vectorParams.empty() )
7104           {
7105             return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7106           }
7107         }
7108         else
7109         {
7110           switch ( vectorParams.size() )
7111           {
7112             case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7113             case 1:
7114               {
7115                 auto returnVectorParamIt = vectorParams.find( returnParams[0] );
7116                 if ( returnVectorParamIt != vectorParams.end() )
7117                 {
7118                   return generateRAIIHandleCommandEnhanced(
7119                     commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::singular );
7120                 }
7121               }
7122               break;
7123           }
7124         }
7125       }
7126       else if ( isHandleType( commandIt->second.params[returnParams[0]].type.type ) )
7127       {
7128         if ( vectorParams.empty() )
7129         {
7130           return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7131         }
7132       }
7133       else
7134       {
7135         auto returnVectorParamIt = vectorParams.find( returnParams[0] );
7136         if ( returnVectorParamIt == vectorParams.end() )
7137         {
7138           std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7139           if ( isStructureChainAnchor( commandIt->second.params[returnParams[0]].type.type ) )
7140           {
7141             str += generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::chained );
7142           }
7143           return str;
7144         }
7145       }
7146       break;
7147     case 2:
7148       if ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" )
7149       {
7150         if ( vectorParams.size() == 1 )
7151         {
7152           if ( returnParams[0] == vectorParams.begin()->second.lenParam )
7153           {
7154             if ( returnParams[1] == vectorParams.begin()->first )
7155             {
7156               std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7157               if ( isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
7158               {
7159                 str +=
7160                   generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::chained );
7161               }
7162               return str;
7163             }
7164           }
7165         }
7166       }
7167       break;
7168   }
7169   return "";
7170 }
7171 
7172 std::pair<std::string, std::string>
generateRAIIHandleStaticCreate(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7173   VulkanHppGenerator::generateRAIIHandleStaticCreate( std::pair<std::string, HandleData> const &                             handle,
7174                                                       std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7175                                                       std::string const &                                                    enter,
7176                                                       std::string const &                                                    leave ) const
7177 {
7178   std::string singularConstructor, arrayConstructor;
7179 
7180   if ( constructorIt->second.returnType == "VkResult" )
7181   {
7182     std::tie( singularConstructor, arrayConstructor ) = generateRAIIHandleStaticCreateResult( handle, constructorIt, enter, leave );
7183   }
7184   else if ( constructorIt->second.returnType == "void" )
7185   {
7186     // If the return type of the construct method does not return a VkResult, and thus can not fail,
7187     // and thus does not throw an exception, a static create method is not needed.
7188   }
7189   else
7190   {
7191     if ( singularConstructor.empty() && arrayConstructor.empty() )
7192     {
7193       throw std::runtime_error( "Never encountered a function like <" + constructorIt->first + "> !" );
7194     }
7195   }
7196   return std::make_pair( singularConstructor, arrayConstructor );
7197 }
7198 
7199 
7200 std::pair<std::string, std::string>
generateRAIIHandleConstructor(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7201   VulkanHppGenerator::generateRAIIHandleConstructor( std::pair<std::string, HandleData> const &                             handle,
7202                                                      std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7203                                                      std::string const &                                                    enter,
7204                                                      std::string const &                                                    leave ) const
7205 {
7206   std::string singularConstructor, arrayConstructor;
7207   if ( constructorIt->second.returnType == "VkResult" )
7208   {
7209     std::tie( singularConstructor, arrayConstructor ) = generateRAIIHandleConstructorResult( handle, constructorIt, enter, leave );
7210   }
7211   else if ( constructorIt->second.returnType == "void" )
7212   {
7213     std::tie( singularConstructor, arrayConstructor ) = generateRAIIHandleConstructorVoid( handle, constructorIt, enter, leave );
7214   }
7215   if ( singularConstructor.empty() && arrayConstructor.empty() )
7216   {
7217     throw std::runtime_error( "Never encountered a function like <" + constructorIt->first + "> !" );
7218   }
7219   return std::make_pair( singularConstructor, arrayConstructor );
7220 }
7221 
7222 std::pair<std::string, std::string>
generateRAIIHandleStaticCreate1Return2Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const7223   VulkanHppGenerator::generateRAIIHandleStaticCreate1Return2Vector( std::pair<std::string, HandleData> const &         handle,
7224                                                                    std::map<std::string, CommandData>::const_iterator constructorIt,
7225                                                                    std::string const &                                enter,
7226                                                                    std::string const &                                leave,
7227                                                                    size_t                                             returnParam,
7228                                                                    std::map<size_t, VectorParamData> const &          vectorParams ) const
7229 {
7230   if ( returnParam == std::next( vectorParams.begin() )->first )
7231   {
7232     if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
7233     {
7234       if ( constructorIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7235       {
7236         if ( ( constructorIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
7237              !isHandleType( constructorIt->second.params[vectorParams.begin()->first].type.type ) )
7238         {
7239           std::string singularConstructor;
7240           auto        lenParamIt    = constructorIt->second.params.begin() + vectorParams.begin()->second.lenParam;
7241           auto        handleParamIt = constructorIt->second.params.begin() + std::next( vectorParams.begin() )->first;
7242           if ( !checkEquivalentSingularConstructor( handle.second.constructorIts, constructorIt, lenParamIt ) )
7243           {
7244             singularConstructor = generateRAIIHandleStaticCreateVectorSingular( handle, constructorIt, handleParamIt, enter, leave );
7245           }
7246           return std::make_pair( singularConstructor, generateRAIIHandleStaticCreateVector( handle, constructorIt, handleParamIt, enter, leave ) );
7247         }
7248       }
7249     }
7250   }
7251   return std::make_pair( "", "" );
7252 }
7253 
7254 std::pair<std::string, std::string>
generateRAIIHandleConstructor1Return2Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const7255   VulkanHppGenerator::generateRAIIHandleConstructor1Return2Vector( std::pair<std::string, HandleData> const &         handle,
7256                                                                    std::map<std::string, CommandData>::const_iterator constructorIt,
7257                                                                    std::string const &                                enter,
7258                                                                    std::string const &                                leave,
7259                                                                    size_t                                             returnParam,
7260                                                                    std::map<size_t, VectorParamData> const &          vectorParams ) const
7261 {
7262   if ( returnParam == std::next( vectorParams.begin() )->first )
7263   {
7264     if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
7265     {
7266       if ( constructorIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7267       {
7268         if ( ( constructorIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
7269              !isHandleType( constructorIt->second.params[vectorParams.begin()->first].type.type ) )
7270         {
7271           std::string singularConstructor;
7272           auto        lenParamIt    = constructorIt->second.params.begin() + vectorParams.begin()->second.lenParam;
7273           auto        handleParamIt = constructorIt->second.params.begin() + std::next( vectorParams.begin() )->first;
7274           if ( !checkEquivalentSingularConstructor( handle.second.constructorIts, constructorIt, lenParamIt ) )
7275           {
7276             singularConstructor = generateRAIIHandleConstructorVectorSingular( handle, constructorIt, handleParamIt, enter, leave );
7277           }
7278           return std::make_pair( singularConstructor, generateRAIIHandleConstructorVector( handle, constructorIt, handleParamIt, enter, leave ) );
7279         }
7280       }
7281     }
7282   }
7283   return std::make_pair( "", "" );
7284 }
7285 
generateRAIIHandleStaticCreates(std::pair<std::string,HandleData> const & handle) const7286 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleStaticCreates( std::pair<std::string, HandleData> const & handle ) const
7287 {
7288   auto [enter, leave] = generateProtection( handle.second.alias.empty() ? getProtectFromType( handle.first ) : "" );
7289 
7290   std::string singularConstructors, arrayConstructors;
7291   for ( auto constructorIt : handle.second.constructorIts )
7292   {
7293     // there is a non-const parameter with handle type : the to-be-constructed handle
7294 
7295     // check for additional enter/leave guards for the constructors
7296     auto [constructorEnter, constructorLeave] = generateProtection( getProtectFromTitle( constructorIt->second.referencedIn ) );
7297     if ( constructorEnter == enter )
7298     {
7299       constructorEnter.clear();
7300       constructorLeave.clear();
7301     }
7302 
7303     auto [singularConstructor, arrayConstructor] = generateRAIIHandleStaticCreate( handle, constructorIt, constructorEnter, constructorLeave );
7304     arrayConstructors += arrayConstructor;
7305     singularConstructors += singularConstructor;
7306   }
7307   return std::make_pair( singularConstructors, arrayConstructors );
7308 }
7309 
generateRAIIHandleConstructors(std::pair<std::string,HandleData> const & handle) const7310 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleConstructors( std::pair<std::string, HandleData> const & handle ) const
7311 {
7312   auto [enter, leave] = generateProtection( handle.second.alias.empty() ? getProtectFromType( handle.first ) : "" );
7313 
7314   std::string singularConstructors, arrayConstructors;
7315   for ( auto constructorIt : handle.second.constructorIts )
7316   {
7317     // there is a non-const parameter with handle type : the to-be-constructed handle
7318 
7319     // check for additional enter/leave guards for the constructors
7320     auto [constructorEnter, constructorLeave] = generateProtection( getProtectFromTitle( constructorIt->second.referencedIn ) );
7321     if ( constructorEnter == enter )
7322     {
7323       constructorEnter.clear();
7324       constructorLeave.clear();
7325     }
7326 
7327     auto [singularConstructor, arrayConstructor] = generateRAIIHandleConstructor( handle, constructorIt, constructorEnter, constructorLeave );
7328     arrayConstructors += arrayConstructor;
7329     singularConstructors += singularConstructor;
7330   }
7331   singularConstructors += generateRAIIHandleConstructorTakeOwnership( handle );
7332   return std::make_pair( singularConstructors, arrayConstructors );
7333 }
7334 
generateRAIIHandleConstructorArgument(ParamData const & param,bool definition,bool singular,bool takesOwnership) const7335 std::string VulkanHppGenerator::generateRAIIHandleConstructorArgument( ParamData const & param, bool definition, bool singular, bool takesOwnership ) const
7336 {
7337   std::string argument;
7338   if ( param.type.isConstPointer() )
7339   {
7340     assert( param.type.type.starts_with( "Vk" ) );
7341     assert( param.name.starts_with( "p" ) );
7342     std::string argumentName = startLowerCase( stripPrefix( param.name, "p" ) );
7343     std::string argumentType = generateNamespacedType( param.type.type );
7344     if ( param.optional )
7345     {
7346       assert( param.len.empty() );
7347       argument = "VULKAN_HPP_NAMESPACE::Optional<const " + argumentType + "> " + argumentName + ( definition ? "" : " = nullptr" );
7348     }
7349     else if ( param.len.empty() )
7350     {
7351       argument = argumentType + " const & " + argumentName;
7352     }
7353     else if ( singular )
7354     {
7355       argument = argumentType + " const & " + stripPluralS( argumentName, m_tags );
7356     }
7357     else
7358     {
7359       argument = "VULKAN_HPP_NAMESPACE::ArrayProxy<" + argumentType + "> const & " + argumentName;
7360     }
7361   }
7362   else if ( specialPointerTypes.find( param.type.type ) != specialPointerTypes.end() )
7363   {
7364     assert( !param.optional );
7365     assert( param.type.isNonConstPointer() );
7366     argument = param.type.type + " & " + param.name;
7367   }
7368   else if ( ( param.type.isValue() ) && isHandleType( param.type.type ) )
7369   {
7370     if ( takesOwnership )
7371     {
7372       assert( !param.optional );
7373       argument = param.type.type + " " + param.name;
7374     }
7375     else
7376     {
7377       argument = "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + stripPrefix( param.type.type, "Vk" );
7378       if ( param.optional )
7379       {
7380         argument = "VULKAN_HPP_NAMESPACE::Optional<const " + argument + ">";
7381       }
7382       argument += " const & " + param.name;
7383     }
7384   }
7385   else
7386   {
7387     assert( !param.optional );
7388     if ( param.arraySizes.empty() )
7389     {
7390       argument = param.type.compose( "VULKAN_HPP_NAMESPACE" ) + " ";
7391     }
7392     else
7393     {
7394       argument = generateStandardArray( param.type.compose( "VULKAN_HPP_NAMESPACE" ), param.arraySizes ) + " const & ";
7395     }
7396     argument += param.name;
7397   }
7398   return argument;
7399 }
7400 
generateRAIIHandleConstructorArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,bool singular,bool takesOwnership) const7401 std::string VulkanHppGenerator::generateRAIIHandleConstructorArguments( std::pair<std::string, HandleData> const &                             handle,
7402                                                                         std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7403                                                                         bool                                                                   singular,
7404                                                                         bool takesOwnership ) const
7405 {
7406   auto [parentType, parentName] = getParentTypeAndName( handle );
7407 
7408   std::string arguments = "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + parentType + " const & " + parentName;
7409   if ( takesOwnership )
7410   {
7411     arguments += ", " + handle.first + " " + generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
7412   }
7413 
7414   if ( constructorIt != m_commands.end() )
7415   {
7416     parentType = "Vk" + parentType;
7417     bool skip  = skipLeadingGrandParent( handle );
7418     for ( size_t i = skip ? 1 : 0; i < constructorIt->second.params.size(); i++ )
7419     {
7420       ParamData const & param = constructorIt->second.params[i];
7421       // filter parent and handle type
7422       if ( ( param.type.type != parentType ) && ( param.type.type != handle.first ) )
7423       {
7424         // the specialPointerTypes are considered const-pointers!
7425         if ( param.type.isNonConstPointer() && ( specialPointerTypes.find( param.type.type ) == specialPointerTypes.end() ) )
7426         {
7427           // this is supposed to be the returned size on an enumeration function!
7428 #if !defined( NDEBUG )
7429           assert( param.type.type == "uint32_t" );
7430           auto typeIt = std::find_if( constructorIt->second.params.begin(),
7431                                       constructorIt->second.params.end(),
7432                                       [&handle]( ParamData const & pd ) { return pd.type.type == handle.first; } );
7433           assert( typeIt != constructorIt->second.params.end() );
7434           assert( typeIt->len == param.name );
7435 #endif
7436           continue;
7437         }
7438         else if ( std::find_if( constructorIt->second.params.begin(),
7439                                 constructorIt->second.params.end(),
7440                                 [&param]( ParamData const & pd ) { return pd.len == param.name; } ) != constructorIt->second.params.end() )
7441         {
7442           // this is the len of an other parameter, which will be mapped to an ArrayProxy
7443           assert( param.type.isValue() && ( param.type.type == "uint32_t" ) );
7444           assert( param.arraySizes.empty() && param.len.empty() && !param.optional );
7445           continue;
7446         }
7447         arguments += ", " + generateRAIIHandleConstructorArgument( param, false, singular, takesOwnership );
7448       }
7449     }
7450   }
7451   return arguments;
7452 }
7453 
7454 std::string
generateRAIIHandleConstructorCallArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams,bool allocatorIsMemberVariable,bool handleParamsAreMembers) const7455   VulkanHppGenerator::generateRAIIHandleConstructorCallArguments( std::pair<std::string, HandleData> const &                             handle,
7456                                                                   std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7457                                                                   bool                     nonConstPointerAsNullptr,
7458                                                                   std::set<size_t> const & singularParams,
7459                                                                   bool                     allocatorIsMemberVariable,
7460                                                                   bool                     handleParamsAreMembers ) const
7461 {
7462   std::string arguments;
7463   bool        encounteredArgument = false;
7464   size_t      i                   = 0;
7465   if ( skipLeadingGrandParent( handle ) )
7466   {
7467     assert( ( 1 < constructorIt->second.params.size() ) && ( m_handles.find( constructorIt->second.params[0].type.type ) != m_handles.end() ) &&
7468             ( m_handles.find( constructorIt->second.params[1].type.type ) != m_handles.end() ) );
7469     arguments += "static_cast<" + constructorIt->second.params[0].type.type + ">( " + constructorIt->second.params[1].name + ".get" +
7470                  stripPrefix( constructorIt->second.params[0].type.type, "Vk" ) + "() )";
7471     encounteredArgument = true;
7472     i                   = 1;
7473   }
7474   for ( ; i < constructorIt->second.params.size(); ++i )
7475   {
7476     ParamData const & param = constructorIt->second.params[i];
7477     if ( encounteredArgument )
7478     {
7479       arguments += ", ";
7480     }
7481     if ( param.type.type == handle.first )
7482     {
7483       assert( param.type.isNonConstPointer() && param.arraySizes.empty() );
7484       if ( param.len.empty() || !singularParams.empty() )
7485       {
7486         assert( !param.optional );
7487         assert( singularParams.empty() || ( param.len == constructorIt->second.params[*singularParams.begin()].name ) );
7488         std::string paramName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
7489         if (handleParamsAreMembers) {
7490           paramName = "m_" + paramName;
7491         }
7492         arguments += "reinterpret_cast<" + handle.first + "*>( &" + paramName + " )";
7493       }
7494       else if ( nonConstPointerAsNullptr )
7495       {
7496         arguments += "nullptr";
7497       }
7498       else
7499       {
7500         arguments += startLowerCase( stripPrefix( param.name, "p" ) ) + ".data()";
7501       }
7502     }
7503     else if ( param.type.type == "VkAllocationCallbacks" )
7504     {
7505       assert( param.optional );
7506       if ( allocatorIsMemberVariable )
7507       {
7508         arguments += "reinterpret_cast<const VkAllocationCallbacks *>( m_allocator )";
7509       }
7510       else
7511       {
7512         arguments += "reinterpret_cast<const VkAllocationCallbacks *>(static_cast<const VULKAN_HPP_NAMESPACE::AllocationCallbacks *>( allocator ) )";
7513       }
7514     }
7515     else if ( m_handles.find( param.type.type ) != m_handles.end() )
7516     {
7517       assert( param.type.isValue() && param.arraySizes.empty() && param.len.empty() );
7518       if ( param.optional )
7519       {
7520         arguments += param.name + " ? static_cast<" + param.type.type + ">( **" + param.name + " ) : 0";
7521       }
7522       else
7523       {
7524         arguments += "static_cast<" + param.type.type + ">( *" + param.name + " )";
7525       }
7526     }
7527     else
7528     {
7529       assert( !param.optional );
7530       arguments += generateCallArgumentEnhanced( constructorIt->second.params, i, nonConstPointerAsNullptr, singularParams, {} );
7531     }
7532     encounteredArgument = true;
7533   }
7534   return arguments;
7535 }
7536 
generateRAIIHandleStaticCreateEnumerate(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::vector<ParamData>::const_iterator lenParamIt,std::string const & enter,std::string const & leave) const7537 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateEnumerate( std::pair<std::string, HandleData> const &                             handle,
7538                                                                          std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7539                                                                          std::vector<ParamData>::const_iterator                                 handleParamIt,
7540                                                                          std::vector<ParamData>::const_iterator                                 lenParamIt,
7541                                                                          std::string const &                                                    enter,
7542                                                                          std::string const &                                                    leave ) const
7543 {
7544   std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
7545   std::string handleType                 = stripPrefix( handle.first, "Vk" );
7546   std::string dispatcherType             = hasParentHandle( handle.first, "VkDevice" ) ? "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher"
7547                                                                                        : "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher";
7548   std::string debugHelper = "";
7549   #ifdef DEBUG_GENERATOR
7550   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
7551   #endif
7552 
7553   const std::string constructorTemplate =
7554     R"(
7555 ${enter}
7556     static android::base::expected<${handleType}s, VULKAN_HPP_NAMESPACE::Result> create( ${constructorArguments} ) ${debugHelper}
7557     {
7558       ${dispatcherType} const * dispatcher = ${parentName}.getDispatcher();
7559       std::vector<${vectorElementType}> ${vectorName};
7560       ${counterType} ${counterName};
7561       VULKAN_HPP_NAMESPACE::Result result;
7562       do
7563       {
7564         result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${firstCallArguments} ) );
7565         if ( ( result == VULKAN_HPP_NAMESPACE::Result::eSuccess ) && ${counterName} )
7566         {
7567           ${vectorName}.resize( ${counterName} );
7568           result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${secondCallArguments} ) );
7569         }
7570       } while ( result == VULKAN_HPP_NAMESPACE::Result::eIncomplete );
7571       if ( result != VULKAN_HPP_NAMESPACE::Result::eSuccess )
7572       {
7573         return android::base::unexpected(result);
7574       }
7575       ${handleType}s ret(nullptr);
7576       ret.reserve( ${counterName} );
7577       for ( auto const & ${handleName} : ${vectorName} )
7578       {
7579         ret.emplace_back( ${parentName}, ${handleConstructorArguments} );
7580       }
7581       return std::move(ret);
7582     }
7583 ${leave})";
7584 
7585   return replaceWithMap( constructorTemplate,
7586                          { { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
7587                            { "constructorCall", constructorIt->first },
7588                            { "counterName", startLowerCase( stripPrefix( lenParamIt->name, "p" ) ) },
7589                            { "counterType", lenParamIt->type.type },
7590                            { "debugHelper", debugHelper },
7591                            { "dispatcherType", dispatcherType },
7592                            { "enter", enter },
7593                            { "firstCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, true, {}, true, true ) },
7594                            { "handleConstructorArguments", handleConstructorArguments },
7595                            { "handleName", startLowerCase( handleType ) },
7596                            { "handleType", handleType },
7597                            { "leave", leave },
7598                            { "parentName", constructorIt->second.params.front().name },
7599                            { "secondCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, true, true ) },
7600                            { "vectorElementType", handleParamIt->type.type },
7601                            { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) } } );
7602 }
7603 
generateRAIIHandleConstructorEnumerate(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::vector<ParamData>::const_iterator lenParamIt,std::string const & enter,std::string const & leave) const7604 std::string VulkanHppGenerator::generateRAIIHandleConstructorEnumerate( std::pair<std::string, HandleData> const &                             handle,
7605                                                                         std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7606                                                                         std::vector<ParamData>::const_iterator                                 handleParamIt,
7607                                                                         std::vector<ParamData>::const_iterator                                 lenParamIt,
7608                                                                         std::string const &                                                    enter,
7609                                                                         std::string const &                                                    leave ) const
7610 {
7611   std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
7612   std::string handleType                 = stripPrefix( handle.first, "Vk" );
7613   std::string dispatcherType             = hasParentHandle( handle.first, "VkDevice" ) ? "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher"
7614                                                                                        : "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher";
7615 
7616   const std::string constructorTemplate =
7617     R"(
7618 ${enter}
7619 #ifndef VULKAN_HPP_NO_EXCEPTIONS
7620     ${handleType}s( ${constructorArguments} )
7621     {
7622       ${dispatcherType} const * dispatcher = ${parentName}.getDispatcher();
7623       std::vector<${vectorElementType}> ${vectorName};
7624       ${counterType} ${counterName};
7625       VULKAN_HPP_NAMESPACE::Result result;
7626       do
7627       {
7628         result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${firstCallArguments} ) );
7629         if ( ( result == VULKAN_HPP_NAMESPACE::Result::eSuccess ) && ${counterName} )
7630         {
7631           ${vectorName}.resize( ${counterName} );
7632           result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${secondCallArguments} ) );
7633         }
7634       } while ( result == VULKAN_HPP_NAMESPACE::Result::eIncomplete );
7635       if ( result == VULKAN_HPP_NAMESPACE::Result::eSuccess )
7636       {
7637         VULKAN_HPP_ASSERT( ${counterName} <= ${vectorName}.size() );
7638         this->reserve( ${counterName} );
7639         for ( auto const & ${handleName} : ${vectorName} )
7640         {
7641           this->emplace_back( ${parentName}, ${handleConstructorArguments} );
7642         }
7643       }
7644       else
7645       {
7646         throwResultException( result, "${constructorCall}" );
7647       }
7648     }
7649 #endif
7650 ${leave})";
7651 
7652   return replaceWithMap( constructorTemplate,
7653                          { { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
7654                            { "constructorCall", constructorIt->first },
7655                            { "counterName", startLowerCase( stripPrefix( lenParamIt->name, "p" ) ) },
7656                            { "counterType", lenParamIt->type.type },
7657                            { "dispatcherType", dispatcherType },
7658                            { "enter", enter },
7659                            { "firstCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, true, {}, true, true ) },
7660                            { "handleConstructorArguments", handleConstructorArguments },
7661                            { "handleName", startLowerCase( handleType ) },
7662                            { "handleType", handleType },
7663                            { "leave", leave },
7664                            { "parentName", constructorIt->second.params.front().name },
7665                            { "secondCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, true, true ) },
7666                            { "vectorElementType", handleParamIt->type.type },
7667                            { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) } } );
7668 }
7669 
7670 std::string
generateRAIIHandleConstructorInitializationList(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator destructorIt,bool takesOwnership) const7671   VulkanHppGenerator::generateRAIIHandleConstructorInitializationList( std::pair<std::string, HandleData> const &                             handle,
7672                                                                        std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7673                                                                        std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator destructorIt,
7674                                                                        bool takesOwnership ) const
7675 {
7676   auto [parentType, parentName] = getParentTypeAndName( handle );
7677   std::string handleName        = generateRAIIHandleConstructorParamName( handle.first, destructorIt );
7678 
7679   std::string initializationList;
7680   if ( destructorIt != m_commands.end() )
7681   {
7682     for ( auto destructorParam : destructorIt->second.params )
7683     {
7684       if ( destructorParam.type.type == "Vk" + parentType )
7685       {
7686         initializationList += "m_" + parentName + "( *" + parentName + " ), ";
7687       }
7688       else if ( destructorParam.type.type == handle.first )
7689       {
7690         if ( takesOwnership )
7691         {
7692           initializationList += "m_" + handleName + "( " + handleName + " ), ";
7693         }
7694       }
7695       else if ( destructorParam.type.type == "VkAllocationCallbacks" )
7696       {
7697         assert( destructorParam.type.isConstPointer() && destructorParam.arraySizes.empty() && destructorParam.len.empty() && destructorParam.optional );
7698         initializationList += "m_allocator( static_cast<const VULKAN_HPP_NAMESPACE::AllocationCallbacks *>( allocator ) ), ";
7699       }
7700       else if ( isHandleType( destructorParam.type.type ) )
7701       {
7702         assert( destructorParam.type.isValue() && destructorParam.arraySizes.empty() && destructorParam.len.empty() && !destructorParam.optional );
7703         initializationList += "m_" + destructorParam.name + "( ";
7704         auto constructorParamIt = std::find_if( constructorIt->second.params.begin(),
7705                                                 constructorIt->second.params.end(),
7706                                                 [&destructorParam]( ParamData const & pd ) { return pd.type.type == destructorParam.type.type; } );
7707         if ( constructorParamIt != constructorIt->second.params.end() )
7708         {
7709           assert( constructorParamIt->type.isValue() && constructorParamIt->arraySizes.empty() && constructorParamIt->len.empty() &&
7710                   !constructorParamIt->optional );
7711           if ( constructorParamIt->type.type == "Vk" + parentType )
7712           {
7713             initializationList += "*";
7714           }
7715           initializationList += constructorParamIt->name;
7716         }
7717         else
7718         {
7719 #if !defined( NDEBUG )
7720           bool found = false;
7721 #endif
7722           for ( auto constructorParam : constructorIt->second.params )
7723           {
7724             auto structureIt = m_structures.find( constructorParam.type.type );
7725             if ( structureIt != m_structures.end() )
7726             {
7727               auto structureMemberIt = findStructMemberItByType( destructorParam.type.type, structureIt->second.members );
7728               if ( structureMemberIt != structureIt->second.members.end() )
7729               {
7730                 assert( constructorParam.type.isConstPointer() && constructorParam.arraySizes.empty() && constructorParam.len.empty() &&
7731                         !constructorParam.optional );
7732                 initializationList += startLowerCase( stripPrefix( constructorParam.name, "p" ) ) + "." + structureMemberIt->name;
7733 #if !defined( NDEBUG )
7734                 found = true;
7735 #endif
7736                 break;
7737               }
7738             }
7739           }
7740           assert( found );
7741         }
7742         initializationList += " ), ";
7743       }
7744       else
7745       {
7746         // we can ignore all other parameters here !
7747       }
7748     }
7749   }
7750   else
7751   {
7752     if ( !handle.second.secondLevelCommands.empty() )
7753     {
7754       assert( !handle.second.constructorIts.empty() );
7755 #if !defined( NDEBUG )
7756       auto constructorCommandIt = m_commands.find( handle.second.constructorIts.front()->first );
7757 #endif
7758       assert( ( constructorCommandIt != m_commands.end() ) && ( 1 < constructorCommandIt->second.params.size() ) );
7759       assert( std::next( constructorCommandIt->second.params.begin() )->type.type == "Vk" + parentType );
7760 
7761       auto commandIt = m_commands.find( *handle.second.secondLevelCommands.begin() );
7762       assert( ( commandIt != m_commands.end() ) && ( 1 < commandIt->second.params.size() ) );
7763       assert( commandIt->second.params.front().type.type == constructorCommandIt->second.params.front().type.type );
7764       assert( std::next( commandIt->second.params.begin() )->type.type == handle.first );
7765 
7766       std::string grandParentType = stripPrefix( commandIt->second.params.front().type.type, "Vk" );
7767       initializationList += "m_" + startLowerCase( grandParentType ) + "( " + parentName + ".get" + grandParentType + "() ), ";
7768     }
7769     if ( takesOwnership )
7770     {
7771       initializationList += "m_" + handleName + "( " + handleName + " ), ";
7772     }
7773   }
7774   return initializationList.empty() ? initializationList : initializationList.substr( 0, initializationList.size() - 2 );
7775 }
7776 
generateRAIIHandleConstructorParamName(std::string const & type,std::map<std::string,CommandData>::const_iterator destructorIt) const7777 std::string VulkanHppGenerator::generateRAIIHandleConstructorParamName( std::string const &                                type,
7778                                                                         std::map<std::string, CommandData>::const_iterator destructorIt ) const
7779 {
7780   if ( destructorIt != m_commands.end() )
7781   {
7782     auto destructorParamIt = std::find_if( destructorIt->second.params.begin(),
7783                                            destructorIt->second.params.end(),
7784                                            [&type]( ParamData const & destructorParam ) { return destructorParam.type.type == type; } );
7785     if ( destructorParamIt != destructorIt->second.params.end() )
7786     {
7787       assert( std::find_if( std::next( destructorParamIt ),
7788                             destructorIt->second.params.end(),
7789                             [&type]( ParamData const & destructorParam ) { return destructorParam.type.type == type; } ) == destructorIt->second.params.end() );
7790       if ( !destructorParamIt->type.isValue() )
7791       {
7792         return startLowerCase( stripPrefix( stripPluralS( destructorParamIt->name, m_tags ), "p" ) );
7793       }
7794       else
7795       {
7796         return destructorParamIt->name;
7797       }
7798     }
7799   }
7800   return startLowerCase( stripPrefix( type, "Vk" ) );
7801 }
7802 
generateRAIIHandleStaticCreateResult(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7803 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleStaticCreateResult( std::pair<std::string, HandleData> const &         handle,
7804                                                                                               std::map<std::string, CommandData>::const_iterator constructorIt,
7805                                                                                               std::string const &                                enter,
7806                                                                                               std::string const &                                leave ) const
7807 {
7808   assert( !constructorIt->second.successCodes.empty() );
7809   assert( constructorIt->second.successCodes[0] == "VK_SUCCESS" );
7810   switch ( constructorIt->second.successCodes.size() )
7811   {
7812     case 1:
7813       if ( !constructorIt->second.errorCodes.empty() )
7814       {
7815         std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7816         if ( returnParams.size() == 1 )
7817         {
7818           assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7819           std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7820           switch ( vectorParams.size() )
7821           {
7822             case 0:
7823               return std::make_pair( generateRAIIHandleStaticCreateResultSingleSuccessWithErrors1Return0Vector( handle, constructorIt, enter, leave ), "" );
7824             case 1:
7825               if ( returnParams[0] == vectorParams.begin()->first )
7826               {
7827                 if ( isLenByStructMember( constructorIt->second.params[vectorParams.begin()->first].len,
7828                                           constructorIt->second.params[vectorParams.begin()->second.lenParam] ) )
7829                 {
7830                   auto handleParamIt = constructorIt->second.params.begin() + returnParams[0];
7831                   return std::make_pair( "", generateRAIIHandleStaticCreateVector( handle, constructorIt, handleParamIt, enter, leave ) );
7832                 }
7833               }
7834               break;
7835             case 2: return generateRAIIHandleStaticCreate1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7836           }
7837         }
7838       }
7839       break;
7840     case 2:
7841       if ( !constructorIt->second.errorCodes.empty() )
7842       {
7843         std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7844         switch ( returnParams.size() )
7845         {
7846           case 1:
7847             assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7848             {
7849               std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7850               if ( vectorParams.size() == 2 )
7851               {
7852                 return generateRAIIHandleStaticCreate1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7853               }
7854             }
7855             break;
7856           case 2:
7857             if ( constructorIt->second.params[returnParams[0]].type.type == "uint32_t" )
7858             {
7859               assert( isHandleType( constructorIt->second.params[returnParams[1]].type.type ) );
7860               std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7861               if ( vectorParams.size() == 1 )
7862               {
7863                 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
7864                 {
7865                   assert( returnParams[1] == vectorParams.begin()->first );
7866                   assert( constructorIt->second.successCodes[1] == "VK_INCOMPLETE" );
7867                   auto lenParamIt    = constructorIt->second.params.begin() + returnParams[0];
7868                   auto handleParamIt = constructorIt->second.params.begin() + returnParams[1];
7869                   return std::make_pair( "", generateRAIIHandleStaticCreateEnumerate( handle, constructorIt, handleParamIt, lenParamIt, enter, leave ) );
7870                 }
7871               }
7872             }
7873             break;
7874         }
7875       }
7876       break;
7877     case 4:
7878       if ( !constructorIt->second.errorCodes.empty() )
7879       {
7880         std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7881         if ( returnParams.size() == 1 )
7882         {
7883           assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7884           std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7885           if ( vectorParams.size() == 2 )
7886           {
7887             return generateRAIIHandleStaticCreate1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7888           }
7889         }
7890       }
7891       break;
7892   }
7893   return std::make_pair( "", "" );
7894 }
7895 
generateRAIIHandleConstructorResult(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7896 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleConstructorResult( std::pair<std::string, HandleData> const &         handle,
7897                                                                                              std::map<std::string, CommandData>::const_iterator constructorIt,
7898                                                                                              std::string const &                                enter,
7899                                                                                              std::string const &                                leave ) const
7900 {
7901   assert( !constructorIt->second.successCodes.empty() );
7902   assert( constructorIt->second.successCodes[0] == "VK_SUCCESS" );
7903   switch ( constructorIt->second.successCodes.size() )
7904   {
7905     case 1:
7906       if ( !constructorIt->second.errorCodes.empty() )
7907       {
7908         std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7909         if ( returnParams.size() == 1 )
7910         {
7911           assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7912           std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7913           switch ( vectorParams.size() )
7914           {
7915             case 0:
7916               return std::make_pair( generateRAIIHandleConstructorResultSingleSuccessWithErrors1Return0Vector( handle, constructorIt, enter, leave ), "" );
7917             case 1:
7918               if ( returnParams[0] == vectorParams.begin()->first )
7919               {
7920                 if ( isLenByStructMember( constructorIt->second.params[vectorParams.begin()->first].len,
7921                                           constructorIt->second.params[vectorParams.begin()->second.lenParam] ) )
7922                 {
7923                   auto handleParamIt = constructorIt->second.params.begin() + returnParams[0];
7924                   return std::make_pair( "", generateRAIIHandleConstructorVector( handle, constructorIt, handleParamIt, enter, leave ) );
7925                 }
7926               }
7927               break;
7928             case 2: return generateRAIIHandleConstructor1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7929           }
7930         }
7931       }
7932       break;
7933     case 2:
7934       if ( !constructorIt->second.errorCodes.empty() )
7935       {
7936         std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7937         switch ( returnParams.size() )
7938         {
7939           case 1:
7940             assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7941             {
7942               std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7943               if ( vectorParams.size() == 2 )
7944               {
7945                 return generateRAIIHandleConstructor1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7946               }
7947             }
7948             break;
7949           case 2:
7950             if ( constructorIt->second.params[returnParams[0]].type.type == "uint32_t" )
7951             {
7952               assert( isHandleType( constructorIt->second.params[returnParams[1]].type.type ) );
7953               std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7954               if ( vectorParams.size() == 1 )
7955               {
7956                 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
7957                 {
7958                   assert( returnParams[1] == vectorParams.begin()->first );
7959                   assert( constructorIt->second.successCodes[1] == "VK_INCOMPLETE" );
7960                   auto lenParamIt    = constructorIt->second.params.begin() + returnParams[0];
7961                   auto handleParamIt = constructorIt->second.params.begin() + returnParams[1];
7962                   return std::make_pair( "", generateRAIIHandleConstructorEnumerate( handle, constructorIt, handleParamIt, lenParamIt, enter, leave ) );
7963                 }
7964               }
7965             }
7966             break;
7967         }
7968       }
7969       break;
7970     case 4:
7971       if ( !constructorIt->second.errorCodes.empty() )
7972       {
7973         std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7974         if ( returnParams.size() == 1 )
7975         {
7976           assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7977           std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7978           if ( vectorParams.size() == 2 )
7979           {
7980             return generateRAIIHandleConstructor1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7981           }
7982         }
7983       }
7984       break;
7985   }
7986   return std::make_pair( "", "" );
7987 }
7988 
generateRAIIHandleStaticCreateToConstructorArgument(ParamData const & param,bool singular) const7989 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateToConstructorArgument( ParamData const & param, bool singular ) const
7990 {
7991   std::string argument;
7992   if ( param.type.isConstPointer() )
7993   {
7994     assert( param.type.type.starts_with( "Vk" ) );
7995     assert( param.name.starts_with( "p" ) );
7996     std::string argumentName = startLowerCase( stripPrefix( param.name, "p" ) );
7997     std::string argumentType = generateNamespacedType( param.type.type );
7998     if ( param.optional )
7999     {
8000       assert( param.len.empty() );
8001       argument = argumentName;
8002     }
8003     else if ( param.len.empty() )
8004     {
8005       argument = argumentName;
8006     }
8007     else if ( singular )
8008     {
8009       argument = stripPluralS( argumentName, m_tags );
8010     }
8011     else
8012     {
8013       argument = argumentName;
8014     }
8015   }
8016   else if ( specialPointerTypes.find( param.type.type ) != specialPointerTypes.end() )
8017   {
8018     assert( !param.optional );
8019     assert( param.type.isNonConstPointer() );
8020     argument = param.name;
8021   }
8022   else if ( ( param.type.isValue() ) && isHandleType( param.type.type ) )
8023   {
8024     argument += param.name;
8025   }
8026   else
8027   {
8028     assert( !param.optional );
8029     argument += param.name;
8030   }
8031   return argument;
8032 }
8033 
generateRAIIHandleStaticCreateToConstructorArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt) const8034 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateToConstructorArguments(
8035   std::pair<std::string, HandleData> const & handle,
8036   std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt ) const
8037 {
8038   auto [parentType, parentName] = getParentTypeAndName( handle );
8039 
8040   std::string arguments = parentName;
8041 
8042   arguments += ", " + generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8043 
8044   if ( constructorIt != m_commands.end() )
8045   {
8046     parentType = "Vk" + parentType;
8047     bool skip  = skipLeadingGrandParent( handle );
8048     for ( size_t i = skip ? 1 : 0; i < constructorIt->second.params.size(); i++ )
8049     {
8050       ParamData const & param = constructorIt->second.params[i];
8051       // filter parent and handle type
8052       if ( ( param.type.type != parentType ) && ( param.type.type != handle.first ) )
8053       {
8054         // the specialPointerTypes are considered const-pointers!
8055         if ( param.type.isNonConstPointer() && ( specialPointerTypes.find( param.type.type ) == specialPointerTypes.end() ) )
8056         {
8057           // this is supposed to be the returned size on an enumeration function!
8058 #if !defined( NDEBUG )
8059           assert( param.type.type == "uint32_t" );
8060           auto typeIt = std::find_if( constructorIt->second.params.begin(),
8061                                       constructorIt->second.params.end(),
8062                                       [&handle]( ParamData const & pd ) { return pd.type.type == handle.first; } );
8063           assert( typeIt != constructorIt->second.params.end() );
8064           assert( typeIt->len == param.name );
8065 #endif
8066           continue;
8067         }
8068         else if ( std::find_if( constructorIt->second.params.begin(),
8069                                 constructorIt->second.params.end(),
8070                                 [&param]( ParamData const & pd ) { return pd.len == param.name; } ) != constructorIt->second.params.end() )
8071         {
8072           // this is the len of an other parameter, which will be mapped to an ArrayProxy
8073           assert( param.type.isValue() && ( param.type.type == "uint32_t" ) );
8074           assert( param.arraySizes.empty() && param.len.empty() && !param.optional );
8075           continue;
8076         }
8077         arguments += ", " + generateRAIIHandleStaticCreateToConstructorArgument(param, false);
8078       }
8079     }
8080   }
8081   return arguments;
8082 }
8083 
generateRAIIHandleStaticCreateResultSingleSuccessWithErrors1Return0Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8084 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateResultSingleSuccessWithErrors1Return0Vector(
8085   std::pair<std::string, HandleData> const &                             handle,
8086   std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8087   std::string const &                                                    enter,
8088   std::string const &                                                    leave ) const
8089 {
8090   auto [parentType, parentName] = getParentTypeAndName( handle );
8091 
8092   std::string getDispatcher = parentName + ".getDispatcher()";
8093 
8094   std::string staticCreateArguments = generateRAIIHandleConstructorArguments( handle, constructorIt, false, false );
8095 
8096   std::string callArguments = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, false, false );
8097 
8098   std::string localParamType = handle.first;
8099   std::string localParamName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8100 
8101   std::string callConstructorArguments =  generateRAIIHandleStaticCreateToConstructorArguments( handle, handle.second.destructorIt );
8102 
8103   std::string debugHelper = "";
8104   #ifdef DEBUG_GENERATOR
8105   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8106   #endif
8107 
8108   const std::string constructorTemplate =
8109     R"(
8110 ${enter}
8111     static android::base::expected<${handleType}, VULKAN_HPP_NAMESPACE::Result> create( ${staticCreateArguments} ) ${debugHelper}
8112     {
8113       ${localParamType} ${localParamName};
8114       VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( ${getDispatcher}->${constructorCall}( ${callArguments} ) );
8115       if ( ${failureCheck} )
8116       {
8117         return android::base::unexpected(result);
8118       }
8119 
8120       return VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}(${callConstructorArguments});
8121     }
8122 ${leave})";
8123 
8124   return replaceWithMap( constructorTemplate,
8125                          { { "callArguments", callArguments },
8126                            { "staticCreateArguments", staticCreateArguments },
8127                            { "callConstructorArguments", callConstructorArguments },
8128                            { "constructorCall", constructorIt->first },
8129                            { "debugHelper", debugHelper },
8130                            { "enter", enter },
8131                            { "failureCheck", generateFailureCheck( constructorIt->second.successCodes ) },
8132                            { "getDispatcher", getDispatcher },
8133                            { "leave", leave },
8134                            { "localParamName", localParamName },
8135                            { "localParamType", localParamType },
8136                            { "handleType", stripPrefix( handle.first, "Vk" ) } } );
8137 }
8138 
generateRAIIHandleConstructorResultSingleSuccessWithErrors1Return0Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8139 std::string VulkanHppGenerator::generateRAIIHandleConstructorResultSingleSuccessWithErrors1Return0Vector(
8140   std::pair<std::string, HandleData> const &                             handle,
8141   std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8142   std::string const &                                                    enter,
8143   std::string const &                                                    leave ) const
8144 {
8145   auto [parentType, parentName] = getParentTypeAndName( handle );
8146 
8147   std::string getDispatcher = parentName + ".getDispatcher()";
8148   std::string dispatcherInitializer, dispatcherInit;
8149   if ( ( handle.first != "VkInstance" ) && ( handle.first != "VkDevice" ) )
8150   {
8151     dispatcherInitializer = "m_dispatcher( " + getDispatcher + " )";
8152   }
8153   else
8154   {
8155     std::string handleType = stripPrefix( handle.first, "Vk" );
8156     dispatcherInit         = "\n        m_dispatcher.reset( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + handleType + "Dispatcher( " + parentName +
8157                      ".getDispatcher()->vkGet" + handleType + "ProcAddr, static_cast<" + handle.first + ">( m_" + startLowerCase( handleType ) + " ) ) );";
8158   }
8159 
8160   std::string constructorArguments = generateRAIIHandleConstructorArguments( handle, constructorIt, false, false );
8161 
8162   std::string callArguments = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, handle.second.destructorIt != m_commands.end(), false );
8163 
8164   std::string initializationList = generateRAIIHandleConstructorInitializationList( handle, constructorIt, handle.second.destructorIt, false );
8165   if ( !initializationList.empty() && !dispatcherInitializer.empty() )
8166   {
8167     initializationList += ", ";
8168   }
8169 
8170   const std::string constructorTemplate =
8171     R"(
8172 ${enter}
8173 #ifndef VULKAN_HPP_NO_EXCEPTIONS
8174     ${handleType}( ${constructorArguments} )
8175       : ${initializationList}${dispatcherInitializer}
8176     {
8177       VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( ${getDispatcher}->${constructorCall}( ${callArguments} ) );
8178       if ( ${failureCheck} )
8179       {
8180         throwResultException( result, "${constructorCall}" );
8181       }${dispatcherInit}
8182     }
8183 #endif
8184 ${leave})";
8185 
8186   return replaceWithMap( constructorTemplate,
8187                          { { "callArguments", callArguments },
8188                            { "constructorArguments", constructorArguments },
8189                            { "constructorCall", constructorIt->first },
8190                            { "dispatcherInitializer", dispatcherInitializer },
8191                            { "dispatcherInit", dispatcherInit },
8192                            { "enter", enter },
8193                            { "failureCheck", generateFailureCheck( constructorIt->second.successCodes ) },
8194                            { "getDispatcher", getDispatcher },
8195                            { "leave", leave },
8196                            { "handleType", stripPrefix( handle.first, "Vk" ) },
8197                            { "initializationList", initializationList } } );
8198 }
8199 
generateRAIIHandleConstructorTakeOwnership(std::pair<std::string,HandleData> const & handle) const8200 std::string VulkanHppGenerator::generateRAIIHandleConstructorTakeOwnership( std::pair<std::string, HandleData> const & handle ) const
8201 {
8202   std::string handleType = stripPrefix( handle.first, "Vk" );
8203   std::string handleName = startLowerCase( handleType );
8204 
8205   auto [parentType, parentName] = getParentTypeAndName( handle );
8206 
8207   std::string constructorArguments = generateRAIIHandleConstructorArguments( handle, handle.second.destructorIt, false, true );
8208   std::string initializationList   = generateRAIIHandleConstructorInitializationList( handle, handle.second.destructorIt, handle.second.destructorIt, true );
8209   assert( !handle.second.constructorIts.empty() );
8210   if ( 1 < handle.second.constructorIts[0]->second.successCodes.size() && ( handle.second.constructorIts[0]->second.successCodes[1] != "VK_INCOMPLETE" ) )
8211   {
8212 #if !defined( NDEBUG )
8213     for ( size_t i = 1; i < handle.second.constructorIts.size(); ++i )
8214     {
8215       assert( 1 < handle.second.constructorIts[i]->second.successCodes.size() );
8216     }
8217 #endif
8218     constructorArguments += ", VULKAN_HPP_NAMESPACE::Result successCode = VULKAN_HPP_NAMESPACE::Result::eSuccess";
8219     initializationList += ", m_constructorSuccessCode( successCode )";
8220   }
8221 
8222   std::string dispatcherInitializer;
8223   if ( ( handle.first != "VkInstance" ) && ( handle.first != "VkDevice" ) )
8224   {
8225     dispatcherInitializer = "m_dispatcher( " + parentName + ".getDispatcher() )";
8226   }
8227   if ( !initializationList.empty() && !dispatcherInitializer.empty() )
8228   {
8229     initializationList += ", ";
8230   }
8231 
8232   std::string dispatcherInit;
8233   if ( ( handle.first == "VkDevice" ) || ( handle.first == "VkInstance" ) )
8234   {
8235     dispatcherInit = "\n        m_dispatcher.reset( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + handleType + "Dispatcher( " + parentName +
8236                      ".getDispatcher()->vkGet" + handleType + "ProcAddr, static_cast<" + handle.first + ">( m_" + startLowerCase( handleType ) + " ) ) );";
8237   }
8238 
8239   const std::string constructorTemplate =
8240     R"(
8241     ${handleType}( ${constructorArguments} )
8242       : ${initializationList}${dispatcherInitializer}
8243     {${dispatcherInit}}
8244 )";
8245 
8246   return replaceWithMap( constructorTemplate,
8247                          { { "constructorArguments", constructorArguments },
8248                            { "dispatcherInitializer", dispatcherInitializer },
8249                            { "dispatcherInit", dispatcherInit },
8250                            { "handleType", handleType },
8251                            { "initializationList", initializationList } } );
8252 }
8253 
generateRAIIHandleStaticCreateVector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8254 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateVector( std::pair<std::string, HandleData> const &                             handle,
8255                                                                       std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8256                                                                       std::vector<ParamData>::const_iterator                                 handleParamIt,
8257                                                                       std::string const &                                                    enter,
8258                                                                       std::string const &                                                    leave ) const
8259 {
8260   std::string vectorSize;
8261   auto        lenIt = std::find_if( constructorIt->second.params.begin(),
8262                                     constructorIt->second.params.end(),
8263                                     [&handleParamIt]( ParamData const & pd ) { return pd.name == handleParamIt->len; } );
8264   if ( lenIt == constructorIt->second.params.end() )
8265   {
8266     std::vector<std::string> lenParts = tokenize( handleParamIt->len, "->" );
8267     assert( lenParts.size() == 2 );
8268     lenIt = std::find_if(
8269       constructorIt->second.params.begin(), constructorIt->second.params.end(), [&lenParts]( ParamData const & pd ) { return pd.name == lenParts[0]; } );
8270 #if !defined( NDEBUG )
8271     assert( lenIt != constructorIt->second.params.end() );
8272     auto structureIt = m_structures.find( lenIt->type.type );
8273     assert( structureIt != m_structures.end() );
8274     assert( isStructMember( lenParts[1], structureIt->second.members ) );
8275     assert( constructorIt->second.successCodes.size() == 1 );
8276 #endif
8277     vectorSize = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
8278   }
8279   else
8280   {
8281     auto arrayIt = std::find_if( constructorIt->second.params.begin(),
8282                                  constructorIt->second.params.end(),
8283                                  [&lenIt, &handleParamIt]( ParamData const & pd ) { return ( pd.len == lenIt->name ) && ( pd.name != handleParamIt->name ); } );
8284     assert( arrayIt != constructorIt->second.params.end() );
8285     vectorSize = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + ".size()";
8286   }
8287 
8288   std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
8289   std::string handleType                 = stripPrefix( handle.first, "Vk" );
8290   std::string successCodePassToElement   = ( 1 < constructorIt->second.successCodes.size() ) ? ", result" : "";
8291 
8292   std::string debugHelper = "";
8293   #ifdef DEBUG_GENERATOR
8294   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8295   #endif
8296 
8297   const std::string constructorTemplate =
8298     R"(
8299 ${enter}
8300     static android::base::expected<${handleType}s, VULKAN_HPP_NAMESPACE::Result> create( ${staticCreateArguments} ) ${debugHelper}
8301     {
8302       VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher const * dispatcher = ${parentName}.getDispatcher();
8303       std::vector<${vectorElementType}> ${vectorName}( ${vectorSize} );
8304       VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${callArguments} ) );
8305       if ( ${successCheck} )
8306       {
8307         VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}s ret(nullptr);
8308         ret.reserve( ${vectorSize} );
8309         for ( auto const & ${handleName} : ${vectorName} )
8310         {
8311           ret.emplace_back( ${parentName}, ${handleConstructorArguments}${successCodePassToElement} );
8312         }
8313         return std::move(ret);
8314       }
8315       else
8316       {
8317         return android::base::unexpected(result);
8318       }
8319     }
8320 ${leave})";
8321 
8322   return replaceWithMap( constructorTemplate,
8323                          { { "callArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, false, true ) },
8324                            { "staticCreateArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
8325                            { "constructorCall", constructorIt->first },
8326                            { "debugHelper", debugHelper },
8327                            { "enter", enter },
8328                            { "handleConstructorArguments", handleConstructorArguments },
8329                            { "handleName", startLowerCase( handleType ) },
8330                            { "handleType", handleType },
8331                            { "leave", leave },
8332                            { "parentName", constructorIt->second.params.front().name },
8333                            { "successCheck", generateSuccessCheck( constructorIt->second.successCodes ) },
8334                            { "successCodePassToElement", successCodePassToElement },
8335                            { "vectorElementType", handleParamIt->type.type },
8336                            { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) },
8337                            { "vectorSize", vectorSize } } );
8338 }
8339 
generateRAIIHandleConstructorVector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8340 std::string VulkanHppGenerator::generateRAIIHandleConstructorVector( std::pair<std::string, HandleData> const &                             handle,
8341                                                                      std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8342                                                                      std::vector<ParamData>::const_iterator                                 handleParamIt,
8343                                                                      std::string const &                                                    enter,
8344                                                                      std::string const &                                                    leave ) const
8345 {
8346   std::string vectorSize;
8347   auto        lenIt = std::find_if( constructorIt->second.params.begin(),
8348                              constructorIt->second.params.end(),
8349                              [&handleParamIt]( ParamData const & pd ) { return pd.name == handleParamIt->len; } );
8350   if ( lenIt == constructorIt->second.params.end() )
8351   {
8352     std::vector<std::string> lenParts = tokenize( handleParamIt->len, "->" );
8353     assert( lenParts.size() == 2 );
8354     lenIt = std::find_if(
8355       constructorIt->second.params.begin(), constructorIt->second.params.end(), [&lenParts]( ParamData const & pd ) { return pd.name == lenParts[0]; } );
8356 #if !defined( NDEBUG )
8357     assert( lenIt != constructorIt->second.params.end() );
8358     auto structureIt = m_structures.find( lenIt->type.type );
8359     assert( structureIt != m_structures.end() );
8360     assert( isStructMember( lenParts[1], structureIt->second.members ) );
8361     assert( constructorIt->second.successCodes.size() == 1 );
8362 #endif
8363     vectorSize = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
8364   }
8365   else
8366   {
8367     auto arrayIt = std::find_if( constructorIt->second.params.begin(),
8368                                  constructorIt->second.params.end(),
8369                                  [&lenIt, &handleParamIt]( ParamData const & pd ) { return ( pd.len == lenIt->name ) && ( pd.name != handleParamIt->name ); } );
8370     assert( arrayIt != constructorIt->second.params.end() );
8371     vectorSize = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + ".size()";
8372   }
8373 
8374   std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
8375   std::string handleType                 = stripPrefix( handle.first, "Vk" );
8376   std::string successCodePassToElement   = ( 1 < constructorIt->second.successCodes.size() ) ? ", result" : "";
8377 
8378   std::string debugHelper = "";
8379   #ifdef DEBUG_GENERATOR
8380   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8381   #endif
8382 
8383   const std::string constructorTemplate =
8384     R"(
8385 ${enter}
8386 #ifndef VULKAN_HPP_NO_EXCEPTIONS
8387     ${handleType}s( ${constructorArguments} ) ${debugHelper}
8388     {
8389       VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher const * dispatcher = ${parentName}.getDispatcher();
8390       std::vector<${vectorElementType}> ${vectorName}( ${vectorSize} );
8391       VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${callArguments} ) );
8392       if ( ${successCheck} )
8393       {
8394         this->reserve( ${vectorSize} );
8395         for ( auto const & ${handleName} : ${vectorName} )
8396         {
8397           this->emplace_back( ${parentName}, ${handleConstructorArguments}${successCodePassToElement} );
8398         }
8399       }
8400       else
8401       {
8402         throwResultException( result, "${constructorCall}" );
8403       }
8404     }
8405 #endif
8406 ${leave})";
8407 
8408   return replaceWithMap( constructorTemplate,
8409                          { { "callArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, false, true ) },
8410                            { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
8411                            { "constructorCall", constructorIt->first },
8412                            { "debugHelper", debugHelper },
8413                            { "enter", enter },
8414                            { "handleConstructorArguments", handleConstructorArguments },
8415                            { "handleName", startLowerCase( handleType ) },
8416                            { "handleType", handleType },
8417                            { "leave", leave },
8418                            { "parentName", constructorIt->second.params.front().name },
8419                            { "successCheck", generateSuccessCheck( constructorIt->second.successCodes ) },
8420                            { "successCodePassToElement", successCodePassToElement },
8421                            { "vectorElementType", handleParamIt->type.type },
8422                            { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) },
8423                            { "vectorSize", vectorSize } } );
8424 }
8425 
8426 std::string
generateRAIIHandleStaticCreateVectorSingular(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8427   VulkanHppGenerator::generateRAIIHandleStaticCreateVectorSingular( std::pair<std::string, HandleData> const &                             handle,
8428                                                                     std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8429                                                                     std::vector<ParamData>::const_iterator                                 handleParamIt,
8430                                                                     std::string const &                                                    enter,
8431                                                                     std::string const &                                                    leave ) const
8432 {
8433   size_t                            returnParam    = static_cast<size_t>( std::distance( constructorIt->second.params.begin(), handleParamIt ) );
8434   std::map<size_t, VectorParamData> vectorParams   = determineVectorParams( constructorIt->second.params );
8435   std::set<size_t>                  singularParams = determineSingularParams( returnParam, vectorParams );
8436 
8437   auto [parentType, parentName] = getParentTypeAndName( handle );
8438   std::string getDispatcher = parentName + ".getDispatcher()";
8439 
8440   std::string callArguments      = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, singularParams, false, false );
8441   std::string failureCheck = generateFailureCheck( constructorIt->second.successCodes );
8442 
8443   std::string localParamType = handle.first;
8444   std::string localParamName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8445 
8446   std::string callConstructorArguments =  generateRAIIHandleStaticCreateToConstructorArguments( handle, handle.second.destructorIt );
8447 
8448   std::string debugHelper = "";
8449   #ifdef DEBUG_GENERATOR
8450   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8451   #endif
8452 
8453   const std::string singularConstructorTemplate =
8454     R"(
8455 ${enter}
8456     static android::base::expected<${handleType}, VULKAN_HPP_NAMESPACE::Result> create( ${staticCreateArguments} ) ${debugHelper}
8457     {
8458       ${localParamType} ${localParamName};
8459       VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( ${getDispatcher}->${constructorCall}( ${callArguments} ) );
8460       if ( ${failureCheck} )
8461       {
8462         return android::base::unexpected(result);
8463       }
8464       return VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}(${callConstructorArguments});
8465     }
8466 ${leave})";
8467 
8468   return replaceWithMap( singularConstructorTemplate,
8469                          { { "callArguments", callArguments },
8470                            { "callConstructorArguments", callConstructorArguments },
8471                            { "staticCreateArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, true, false ) },
8472                            { "constructorCall", constructorIt->first },
8473                            { "debugHelper", debugHelper },
8474                            { "enter", enter },
8475                            { "failureCheck", failureCheck },
8476                            { "getDispatcher", getDispatcher },
8477                            { "leave", leave },
8478                            { "localParamType", localParamType },
8479                            { "localParamName", localParamName },
8480                            { "handleType", stripPrefix( handle.first, "Vk" ) } } );
8481 }
8482 
8483 std::string
generateRAIIHandleConstructorVectorSingular(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8484   VulkanHppGenerator::generateRAIIHandleConstructorVectorSingular( std::pair<std::string, HandleData> const &                             handle,
8485                                                                    std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8486                                                                    std::vector<ParamData>::const_iterator                                 handleParamIt,
8487                                                                    std::string const &                                                    enter,
8488                                                                    std::string const &                                                    leave ) const
8489 {
8490   size_t                            returnParam    = static_cast<size_t>( std::distance( constructorIt->second.params.begin(), handleParamIt ) );
8491   std::map<size_t, VectorParamData> vectorParams   = determineVectorParams( constructorIt->second.params );
8492   std::set<size_t>                  singularParams = determineSingularParams( returnParam, vectorParams );
8493 
8494   std::string callArguments      = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, singularParams, true, true );
8495   std::string initializationList = generateRAIIHandleConstructorInitializationList( handle, constructorIt, handle.second.destructorIt, false );
8496   assert( !initializationList.empty() );
8497   std::string failureCheck = generateFailureCheck( constructorIt->second.successCodes );
8498   failureCheck             = std::regex_replace( failureCheck, std::regex( "result" ), "m_constructorSuccessCode" );
8499 
8500   std::string debugHelper = "";
8501   #ifdef DEBUG_GENERATOR
8502   debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8503   #endif
8504 
8505   const std::string singularConstructorTemplate =
8506     R"(
8507 ${enter}
8508 #ifndef VULKAN_HPP_NO_EXCEPTIONS
8509     ${handleType}( ${constructorArguments} ) ${debugHelper}
8510       : ${initializationList}, m_dispatcher( ${firstArgument}.getDispatcher() )
8511     {
8512       m_constructorSuccessCode = static_cast<VULKAN_HPP_NAMESPACE::Result>( getDispatcher()->${constructorCall}( ${callArguments} ) );
8513       if ( ${failureCheck} )
8514       {
8515         throwResultException( m_constructorSuccessCode, "${constructorCall}" );
8516       }
8517     }
8518 #endif
8519 ${leave})";
8520 
8521   return replaceWithMap( singularConstructorTemplate,
8522                          { { "initializationList", initializationList },
8523                            { "callArguments", callArguments },
8524                            { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, true, false ) },
8525                            { "constructorCall", constructorIt->first },
8526                            { "debugHelper", debugHelper },
8527                            { "enter", enter },
8528                            { "firstArgument", constructorIt->second.params[0].name },
8529                            { "failureCheck", failureCheck },
8530                            { "leave", leave },
8531                            { "handleType", stripPrefix( handle.first, "Vk" ) } } );
8532 }
8533 
generateRAIIHandleConstructorVoid(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8534 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleConstructorVoid( std::pair<std::string, HandleData> const &         handle,
8535                                                                                            std::map<std::string, CommandData>::const_iterator constructorIt,
8536                                                                                            std::string const &                                enter,
8537                                                                                            std::string const &                                leave ) const
8538 {
8539   assert( constructorIt->second.successCodes.empty() && constructorIt->second.errorCodes.empty() );
8540   std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
8541   if ( returnParams.size() == 1 )
8542   {
8543     assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
8544     std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
8545     if ( vectorParams.empty() )
8546     {
8547       return std::make_pair( generateRAIIHandleConstructorVoid1Return0Vector( handle, constructorIt, enter, leave ), "" );
8548     }
8549   }
8550   return std::make_pair( "", "" );
8551 }
8552 
8553 std::string
generateRAIIHandleConstructorVoid1Return0Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8554   VulkanHppGenerator::generateRAIIHandleConstructorVoid1Return0Vector( std::pair<std::string, HandleData> const &                             handle,
8555                                                                        std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8556                                                                        std::string const &                                                    enter,
8557                                                                        std::string const &                                                    leave ) const
8558 {
8559   std::string callArguments        = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, true, true );
8560   std::string constructorArguments = generateRAIIHandleConstructorArguments( handle, constructorIt, false, false );
8561   std::string initializationList   = generateRAIIHandleConstructorInitializationList( handle, constructorIt, handle.second.destructorIt, false );
8562   if ( !initializationList.empty() )
8563   {
8564     initializationList += ", ";
8565   }
8566 
8567   const std::string constructorTemplate =
8568     R"(
8569 ${enter}    ${handleType}( ${constructorArguments} )
8570       : ${initializationList}m_dispatcher( ${firstArgument}.getDispatcher() )
8571     {
8572       getDispatcher()->${constructorCall}( ${callArguments} );
8573     }
8574 ${leave})";
8575 
8576   return replaceWithMap( constructorTemplate,
8577                          { { "callArguments", callArguments },
8578                            { "constructorArguments", constructorArguments },
8579                            { "constructorCall", constructorIt->first },
8580                            { "enter", enter },
8581                            { "firstArgument", constructorIt->second.params[0].name },
8582                            { "leave", leave },
8583                            { "handleType", stripPrefix( handle.first, "Vk" ) },
8584                            { "initializationList", initializationList } } );
8585 }
8586 
generateRAIIHandleContext(std::pair<std::string,HandleData> const & handle,std::set<std::string> const & specialFunctions) const8587 std::string VulkanHppGenerator::generateRAIIHandleContext( std::pair<std::string, HandleData> const & handle,
8588                                                            std::set<std::string> const &              specialFunctions ) const
8589 {
8590   const std::string contextTemplate = R"(
8591     class Context
8592     {
8593     public:
8594 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8595       Context()
8596         : m_dispatcher( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher(
8597             m_dynamicLoader.getProcAddress<PFN_vkGetInstanceProcAddr>( "vkGetInstanceProcAddr" ) ) )
8598 #else
8599       Context( PFN_vkGetInstanceProcAddr getInstanceProcAddr )
8600         : m_dispatcher( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher( getInstanceProcAddr ) )
8601 #endif
8602       {}
8603 
8604       ~Context() = default;
8605 
8606       Context( Context const & ) = delete;
8607       Context( Context && rhs ) VULKAN_HPP_NOEXCEPT
8608 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8609         : m_dynamicLoader( std::move( rhs.m_dynamicLoader ) )
8610         , m_dispatcher( rhs.m_dispatcher.release() )
8611 #else
8612         : m_dispatcher( rhs.m_dispatcher.release() )
8613 #endif
8614       {}
8615       Context & operator=( Context const & ) = delete;
8616       Context & operator=( Context && rhs ) VULKAN_HPP_NOEXCEPT
8617       {
8618         if ( this != &rhs )
8619         {
8620 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8621           m_dynamicLoader = std::move( rhs.m_dynamicLoader );
8622 #endif
8623           m_dispatcher.reset( rhs.m_dispatcher.release() );
8624         }
8625         return *this;
8626       }
8627 
8628       VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher const * getDispatcher() const
8629       {
8630         VULKAN_HPP_ASSERT( m_dispatcher->getVkHeaderVersion() == VK_HEADER_VERSION );
8631         return &*m_dispatcher;
8632       }
8633 
8634       void swap( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::Context & rhs )
8635       {
8636 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8637         std::swap( m_dynamicLoader, rhs.m_dynamicLoader );
8638 #endif
8639         m_dispatcher.swap( rhs.m_dispatcher );
8640       }
8641 
8642 ${memberFunctionDeclarations}
8643 
8644     private:
8645 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8646       VULKAN_HPP_NAMESPACE::DynamicLoader                                                 m_dynamicLoader;
8647 #endif
8648       std::unique_ptr<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher> m_dispatcher;
8649     };
8650 
8651 )";
8652 
8653   return replaceWithMap( contextTemplate, { { "memberFunctionDeclarations", generateRAIIHandleCommandDeclarations( handle, specialFunctions ) } } );
8654 }
8655 
generateRAIIHandleDestructorCallArguments(std::string const & handleType,std::map<std::string,CommandData>::const_iterator destructorIt) const8656 std::string VulkanHppGenerator::generateRAIIHandleDestructorCallArguments( std::string const &                                handleType,
8657                                                                            std::map<std::string, CommandData>::const_iterator destructorIt ) const
8658 {
8659   std::string arguments;
8660   bool        encounteredArgument = false;
8661   for ( auto param : destructorIt->second.params )
8662   {
8663     if ( encounteredArgument )
8664     {
8665       arguments += ", ";
8666     }
8667     if ( param.type.type == handleType )
8668     {
8669       std::string handleName = param.name;
8670       if ( param.type.isValue() )
8671       {
8672         arguments += "static_cast<" + handleType + ">( m_" + handleName + " )";
8673       }
8674       else
8675       {
8676         arguments += "reinterpret_cast<" + handleType + " const *>( &m_" + stripPluralS( startLowerCase( stripPrefix( handleName, "p" ) ), m_tags ) + " )";
8677       }
8678     }
8679     else if ( param.type.type == "VkAllocationCallbacks" )
8680     {
8681       // vk::AllocationCallbacks is stored as a member of the handle class
8682       arguments += "reinterpret_cast<const VkAllocationCallbacks *>( m_allocator )";
8683     }
8684     else if ( isHandleType( param.type.type ) )
8685     {
8686       assert( param.arraySizes.empty() );
8687       std::string argument = "m_" + param.name;
8688       if ( param.type.isValue() )
8689       {
8690         arguments += "static_cast<" + param.type.type + ">( " + argument + " )";
8691       }
8692       else
8693       {
8694         assert( param.type.isConstPointer() );
8695         assert( !param.len.empty() &&
8696                 ( std::find_if( destructorIt->second.params.begin(),
8697                                 destructorIt->second.params.end(),
8698                                 [&param]( ParamData const & pd ) { return pd.name == param.len; } ) != destructorIt->second.params.end() ) );
8699         arguments += "reinterpret_cast<" + param.type.type + " const *>( &" + argument + " )";
8700       }
8701     }
8702     else
8703     {
8704       assert( ( param.type.type == "uint32_t" ) && param.type.isValue() && param.arraySizes.empty() && param.len.empty() && !param.optional );
8705       assert( std::find_if( destructorIt->second.params.begin(),
8706                             destructorIt->second.params.end(),
8707                             [&param]( ParamData const & pd ) { return pd.len == param.name; } ) != destructorIt->second.params.end() );
8708       arguments += "1";
8709     }
8710     encounteredArgument = true;
8711   }
8712   return arguments;
8713 }
8714 
8715 std::tuple<std::string, std::string, std::string, std::string, std::string, std::string, std::string>
generateRAIIHandleDetails(std::pair<std::string,HandleData> const & handle) const8716   VulkanHppGenerator::generateRAIIHandleDetails( std::pair<std::string, HandleData> const & handle ) const
8717 {
8718   std::string getConstructorSuccessCode;
8719   bool        multiSuccessCodeContructor = isMultiSuccessCodeConstructor( handle.second.constructorIts );
8720   if ( multiSuccessCodeContructor )
8721   {
8722     getConstructorSuccessCode = R"(
8723     VULKAN_HPP_NAMESPACE::Result getConstructorSuccessCode() const
8724     {
8725       return m_constructorSuccessCode;
8726     }
8727 )";
8728   }
8729 
8730   auto [parentType, parentName] = getParentTypeAndName( handle );
8731 
8732   std::string handleName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8733 
8734   std::string clearMembers, moveConstructorInitializerList, moveAssignmentInstructions, memberVariables, swapMembers, releaseMembers;
8735 
8736   if ( handle.second.destructorIt != m_commands.end() )
8737   {
8738     moveAssignmentInstructions = "          clear();";
8739 
8740     clearMembers = "        if ( m_" + handleName + " )\n";
8741     clearMembers += "        {\n";
8742     clearMembers += "          getDispatcher()->" + handle.second.destructorIt->first + "( " +
8743                     generateRAIIHandleDestructorCallArguments( handle.first, handle.second.destructorIt ) + " );\n";
8744     clearMembers += "        }";
8745     for ( auto const & destructorParam : handle.second.destructorIt->second.params )
8746     {
8747       std::string memberName, memberType;
8748       if ( destructorParam.type.type == "Vk" + parentType )
8749       {
8750         memberName = parentName;
8751         memberType = "VULKAN_HPP_NAMESPACE::" + parentType;
8752       }
8753       else if ( destructorParam.type.type == handle.first )
8754       {
8755         memberName = handleName;
8756         memberType = generateNamespacedType( handle.first );
8757       }
8758       else if ( std::find_if( handle.second.destructorIt->second.params.begin(),
8759                               handle.second.destructorIt->second.params.end(),
8760                               [&destructorParam]( ParamData const & pd )
8761                               { return pd.len == destructorParam.name; } ) == handle.second.destructorIt->second.params.end() )
8762       {
8763         std::string name = destructorParam.name;
8764         if ( !destructorParam.type.isValue() )
8765         {
8766           name = startLowerCase( stripPrefix( name, "p" ) );
8767         }
8768         memberName = name;
8769         memberType = destructorParam.type.compose( "VULKAN_HPP_NAMESPACE" );
8770       }
8771       if ( !memberName.empty() )
8772       {
8773         clearMembers += "\n      m_" + memberName + " = nullptr;";
8774         moveConstructorInitializerList += "m_" + memberName + "( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + memberName + ", {} ) ), ";
8775         moveAssignmentInstructions +=
8776           "\n          m_" + memberName + " = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + memberName + ", {} );";
8777         memberVariables += "\n    " + memberType + " m_" + memberName + " = {};";
8778         swapMembers += "\n      std::swap( m_" + memberName + ", rhs.m_" + memberName + " );";
8779         if ( destructorParam.type.type != handle.first )
8780         {
8781           releaseMembers += "\n      m_" + memberName + " = nullptr;";
8782         }
8783       }
8784     }
8785   }
8786   else
8787   {
8788     if ( !handle.second.secondLevelCommands.empty() )
8789     {
8790       assert( !handle.second.constructorIts.empty() );
8791       assert( !handle.second.constructorIts.front()->second.params.empty() );
8792       auto const & frontType = handle.second.constructorIts.front()->second.params.front().type.type;
8793       assert( isHandleType( frontType ) );
8794 #if !defined( NDEBUG )
8795       auto handleIt = m_handles.find( "Vk" + parentType );
8796 #endif
8797       assert( handleIt != m_handles.end() );
8798       assert( handleIt->second.parent == frontType );
8799       std::string frontName = handle.second.constructorIts.front()->second.params.front().name;
8800 
8801       clearMembers += "\n        m_" + frontName + " = nullptr;";
8802       moveConstructorInitializerList = "m_" + frontName + "( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + frontName + ", {} ) ), ";
8803       moveAssignmentInstructions =
8804         "\n          m_" + frontName + " = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + frontName + ", {} );";
8805       memberVariables = "\n    VULKAN_HPP_NAMESPACE::" + stripPrefix( frontType, "Vk" ) + " m_" + frontName + " = {};";
8806       swapMembers     = "\n      std::swap( m_" + frontName + ", rhs.m_" + frontName + " );";
8807       releaseMembers += "\n        m_" + frontName + " = nullptr;";
8808     }
8809     clearMembers += "\n        m_" + handleName + " = nullptr;";
8810     moveConstructorInitializerList += "m_" + handleName + "( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + handleName + ", {} ) ), ";
8811     moveAssignmentInstructions +=
8812       "\n          m_" + handleName + " = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + handleName + ", {} );";
8813     memberVariables += "\n    " + generateNamespacedType( handle.first ) + " m_" + handleName + " = {};";
8814     swapMembers += "\n      std::swap( m_" + handleName + ", rhs.m_" + handleName + " );";
8815   }
8816 
8817   if ( multiSuccessCodeContructor )
8818   {
8819     clearMembers += "\n        m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::Result::eErrorUnknown;";
8820     memberVariables += "\n    VULKAN_HPP_NAMESPACE::Result m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::Result::eErrorUnknown;";
8821     swapMembers += "\n      std::swap( m_constructorSuccessCode, rhs.m_constructorSuccessCode );";
8822     moveConstructorInitializerList +=
8823       "m_constructorSuccessCode( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_constructorSuccessCode, {} ) ), ";
8824     moveAssignmentInstructions +=
8825       "\n          m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_constructorSuccessCode, {} );";
8826     releaseMembers += "\n        m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::Result::eErrorUnknown;";
8827   }
8828 
8829   if ( handle.first == "VkInstance" )
8830   {
8831     memberVariables += "\n      std::unique_ptr<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher> m_dispatcher;";
8832   }
8833   else if ( handle.first == "VkDevice" )
8834   {
8835     memberVariables += "\n      std::unique_ptr<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher> m_dispatcher;";
8836   }
8837   else if ( handle.second.constructorIts.front()->second.params.front().type.type == "VkDevice" )
8838   {
8839     memberVariables += "\n      VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher const * m_dispatcher = nullptr;";
8840   }
8841   else
8842   {
8843     memberVariables += "\n      VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher const * m_dispatcher = nullptr;";
8844   }
8845   clearMembers += "\n        m_dispatcher = nullptr;";
8846   swapMembers += "\n      std::swap( m_dispatcher, rhs.m_dispatcher );";
8847   releaseMembers += "\n        m_dispatcher = nullptr;";
8848   releaseMembers += "\n        return VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( m_" + handleName + ", nullptr );";
8849 
8850   if ( ( handle.first == "VkInstance" ) || ( handle.first == "VkDevice" ) )
8851   {
8852     moveConstructorInitializerList += "m_dispatcher( rhs.m_dispatcher.release() )";
8853     moveAssignmentInstructions += "\n        m_dispatcher.reset( rhs.m_dispatcher.release() );";
8854   }
8855   else
8856   {
8857     moveConstructorInitializerList += "m_dispatcher( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_dispatcher, nullptr ) )";
8858     moveAssignmentInstructions += "\n        m_dispatcher = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_dispatcher, nullptr );";
8859   }
8860 
8861   return std::make_tuple(
8862     clearMembers, getConstructorSuccessCode, memberVariables, moveConstructorInitializerList, moveAssignmentInstructions, swapMembers, releaseMembers );
8863 }
8864 
generateRAIIHandleForwardDeclarations(std::vector<RequireData> const & requireData,std::string const & title) const8865 std::string VulkanHppGenerator::generateRAIIHandleForwardDeclarations( std::vector<RequireData> const & requireData, std::string const & title ) const
8866 {
8867   std::string str;
8868   for ( auto const & require : requireData )
8869   {
8870     for ( auto const & type : require.types )
8871     {
8872       auto handleIt = m_handles.find( type );
8873       if ( handleIt != m_handles.end() )
8874       {
8875         str += "  class " + stripPrefix( handleIt->first, "Vk" ) + ";\n";
8876       }
8877     }
8878   }
8879   return addTitleAndProtection( title, str );
8880 }
8881 
generateRAIIHandles() const8882 std::string VulkanHppGenerator::generateRAIIHandles() const
8883 {
8884   const std::string raiiHandlesTemplate = R"(
8885   //========================================
8886   //=== RAII HANDLE forward declarations ===
8887   //========================================
8888 
8889 ${forwardDeclarations}
8890 
8891   //====================
8892   //=== RAII HANDLES ===
8893   //====================
8894 
8895 ${raiiHandles}
8896 )";
8897 
8898   std::string forwardDeclarations;
8899   for ( auto const & feature : m_features )
8900   {
8901     forwardDeclarations += generateRAIIHandleForwardDeclarations( feature.second.requireData, feature.first );
8902   }
8903   for ( auto const & extIt : m_extensionsByNumber )
8904   {
8905     forwardDeclarations += generateRAIIHandleForwardDeclarations( extIt.second->second.requireData, extIt.second->first );
8906   }
8907 
8908   std::set<std::string> listedHandles;
8909   auto                  handleIt = m_handles.begin();
8910   assert( handleIt->first.empty() );
8911   std::string raiiHandles = generateRAIIHandleContext( *handleIt, m_RAIISpecialFunctions );
8912   for ( ++handleIt; handleIt != m_handles.end(); ++handleIt )
8913   {
8914     raiiHandles += generateRAIIHandle( *handleIt, listedHandles, m_RAIISpecialFunctions );
8915   }
8916   return replaceWithMap( raiiHandlesTemplate, { { "forwardDeclarations", forwardDeclarations }, { "raiiHandles", raiiHandles } } );
8917 }
8918 
generateRAIIHandleSingularConstructorArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt) const8919 std::string VulkanHppGenerator::generateRAIIHandleSingularConstructorArguments( std::pair<std::string, HandleData> const &         handle,
8920                                                                                 std::map<std::string, CommandData>::const_iterator constructorIt ) const
8921 {
8922   std::string arguments = startLowerCase( stripPrefix( handle.first, "Vk" ) );
8923   if ( handle.second.destructorIt != m_commands.end() )
8924   {
8925     auto [parentType, parentName] = getParentTypeAndName( handle );
8926     parentType                    = "Vk" + parentType;
8927     for ( auto const & destructorParam : handle.second.destructorIt->second.params )
8928     {
8929       if ( ( destructorParam.type.type != parentType ) && ( destructorParam.type.type != handle.first ) &&
8930            ( std::find_if( handle.second.destructorIt->second.params.begin(),
8931                            handle.second.destructorIt->second.params.end(),
8932                            [&destructorParam]( ParamData const & pd )
8933                            { return pd.len == destructorParam.name; } ) == handle.second.destructorIt->second.params.end() ) )
8934       {
8935         if ( std::find_if( constructorIt->second.params.begin(),
8936                            constructorIt->second.params.end(),
8937                            [&destructorParam]( ParamData const & pd )
8938                            { return pd.type.type == destructorParam.type.type; } ) != constructorIt->second.params.end() )
8939         {
8940           if ( isHandleType( destructorParam.type.type ) )
8941           {
8942             assert( destructorParam.type.isValue() );
8943             arguments += ", static_cast<" + destructorParam.type.type + ">( *" + destructorParam.name + " )";
8944           }
8945           else
8946           {
8947             assert( destructorParam.type.type == "VkAllocationCallbacks" );
8948             arguments += ", allocator";
8949           }
8950         }
8951         else
8952         {
8953 #if !defined( NDEBUG )
8954           bool found = false;
8955 #endif
8956           for ( auto const & constructorParam : constructorIt->second.params )
8957           {
8958             auto structureIt = m_structures.find( constructorParam.type.type );
8959             if ( structureIt != m_structures.end() )
8960             {
8961               auto memberIt = findStructMemberItByType( destructorParam.type.type, structureIt->second.members );
8962               if ( memberIt != structureIt->second.members.end() )
8963               {
8964 #if !defined( NDEBUG )
8965                 found = true;
8966 #endif
8967                 assert( !constructorParam.type.isValue() );
8968                 std::string argument = startLowerCase( stripPrefix( constructorParam.name, "p" ) ) + "." + memberIt->name;
8969                 if ( isHandleType( memberIt->type.type ) )
8970                 {
8971                   argument = "static_cast<" + memberIt->type.type + ">( " + argument + " )";
8972                 }
8973                 arguments += ", " + argument;
8974                 break;
8975               }
8976             }
8977           }
8978           assert( found );
8979         }
8980       }
8981     }
8982   }
8983   return arguments;
8984 }
8985 
generateRAIIHandleVectorSizeCheck(std::string const & name,CommandData const & commandData,size_t initialSkipCount,std::map<size_t,std::vector<size_t>> const & countToVectorMap,std::set<size_t> const & skippedParams) const8986 std::string VulkanHppGenerator::generateRAIIHandleVectorSizeCheck( std::string const &                           name,
8987                                                                    CommandData const &                           commandData,
8988                                                                    size_t                                        initialSkipCount,
8989                                                                    std::map<size_t, std::vector<size_t>> const & countToVectorMap,
8990                                                                    std::set<size_t> const &                      skippedParams ) const
8991 {
8992   std::string const throwTemplate =
8993     R"#(    if ( ${zeroSizeCheck}${firstVectorName}.size() != ${secondVectorName}.size() )
8994   {
8995     #ifndef VULKAN_HPP_NO_EXCEPTIONS
8996     throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() != ${secondVectorName}.size()" );
8997     #else
8998     LOG(FATAL) << VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() != ${secondVectorName}.size()";
8999     #endif
9000   })#";
9001 
9002   std::string const throwTemplateVoid =
9003     R"#(    if ( ${zeroSizeCheck}${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} ) )
9004   {
9005     #ifndef VULKAN_HPP_NO_EXCEPTIONS
9006     throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} )" );
9007     #else
9008     LOG(FATAL) << VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} )";
9009     #endif
9010   })#";
9011 
9012   std::string const throwTemplateByLen = R"#(    if ( ${vectorName}.size() != ${sizeValue} )
9013     {
9014       #ifndef VULKAN_HPP_NO_EXCEPTIONS
9015       throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${vectorName}.size() != ${sizeValue}" );
9016       #else
9017       LOG(FATAL) << VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${vectorName}.size() != ${sizeValue}";
9018       #endif
9019     })#";
9020 
9021   std::string className   = stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" );
9022   std::string commandName = generateCommandName( name, commandData.params, initialSkipCount, m_tags );
9023 
9024   std::string sizeChecks;
9025   for ( auto const & cvm : countToVectorMap )
9026   {
9027     size_t      defaultStartIndex = determineDefaultStartIndex( commandData.params, skippedParams );
9028     std::string firstVectorName   = startLowerCase( stripPrefix( commandData.params[cvm.second[0]].name, "p" ) );
9029 
9030     if ( cvm.second.size() == 1 )
9031     {
9032       assert( isLenByStructMember( commandData.params[cvm.second[0]].len, commandData.params[cvm.first] ) );
9033 
9034       std::vector<std::string> lenParts = tokenize( commandData.params[cvm.second[0]].len, "->" );
9035       assert( lenParts.size() == 2 );
9036       std::string sizeValue = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
9037       sizeChecks += replaceWithMap(
9038         throwTemplateByLen, { { "className", className }, { "commandName", commandName }, { "sizeValue", sizeValue }, { "vectorName", firstVectorName } } );
9039     }
9040     else
9041     {
9042       for ( size_t i = 1; i < cvm.second.size(); i++ )
9043       {
9044         std::string secondVectorName  = startLowerCase( stripPrefix( commandData.params[cvm.second[i]].name, "p" ) );
9045         bool        withZeroSizeCheck = commandData.params[cvm.second[i]].optional && ( defaultStartIndex <= cvm.second[i] );
9046         if ( commandData.params[cvm.second[0]].type.type == "void" )
9047         {
9048           assert( commandData.params[cvm.second[i]].type.type == "void" );
9049           std::string firstDataType  = stripPrefix( commandData.params[cvm.second[0]].name, "p" ) + "Type";
9050           std::string secondDataType = stripPrefix( commandData.params[cvm.second[i]].name, "p" ) + "Type";
9051           sizeChecks += replaceWithMap( throwTemplateVoid,
9052                                         { { "firstDataType", firstDataType },
9053                                           { "firstVectorName", firstVectorName },
9054                                           { "className", className },
9055                                           { "commandName", commandName },
9056                                           { "secondDataType", secondDataType },
9057                                           { "secondVectorName", secondVectorName },
9058                                           { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
9059         }
9060         else
9061         {
9062           sizeChecks += replaceWithMap( throwTemplate,
9063                                         { { "firstVectorName", firstVectorName },
9064                                           { "className", className },
9065                                           { "commandName", commandName },
9066                                           { "secondVectorName", secondVectorName },
9067                                           { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
9068         }
9069         if ( i + 1 < cvm.second.size() )
9070         {
9071           sizeChecks += "\n";
9072         }
9073       }
9074     }
9075   }
9076   if ( !sizeChecks.empty() )
9077   {
9078     sizeChecks += "\n";
9079   }
9080 
9081   return sizeChecks;
9082 }
9083 
generateResultAssignment(CommandData const & commandData) const9084 std::string VulkanHppGenerator::generateResultAssignment( CommandData const & commandData ) const
9085 {
9086   std::string resultAssignment;
9087   if ( ( commandData.returnType != "void" ) &&
9088        !( ( commandData.returnType == "VkResult" ) && ( commandData.successCodes.size() == 1 ) && commandData.errorCodes.empty() ) )
9089   {
9090     resultAssignment = commandData.returnType + " result = ";
9091   }
9092   return resultAssignment;
9093 }
9094 
generateResultCheck(CommandData const & commandData,std::string const & className,std::string const & classSeparator,std::string commandName,bool enumerating) const9095 std::string VulkanHppGenerator::generateResultCheck(
9096   CommandData const & commandData, std::string const & className, std::string const & classSeparator, std::string commandName, bool enumerating ) const
9097 {
9098   std::string resultCheck;
9099   if ( !commandData.errorCodes.empty() )
9100   {
9101     std::string successCodeList = generateSuccessCodeList( commandData.successCodes, enumerating );
9102 
9103     std::string const resultCheckTemplate =
9104       R"(resultCheck( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), VULKAN_HPP_NAMESPACE_STRING "::${className}${classSeparator}${commandName}"${successCodeList} );)";
9105 
9106     resultCheck = replaceWithMap(
9107       resultCheckTemplate,
9108       { { "className", className }, { "classSeparator", classSeparator }, { "commandName", commandName }, { "successCodeList", successCodeList } } );
9109   }
9110   return resultCheck;
9111 }
9112 
9113 // Intended only for `enum class Result`!
generateResultExceptions() const9114 std::string VulkanHppGenerator::generateResultExceptions() const
9115 {
9116   const std::string templateString = R"(
9117 ${enter}  class ${className} : public SystemError
9118   {
9119   public:
9120     ${className}( std::string const & message )
9121       : SystemError( make_error_code( ${enumName}::${enumMemberName} ), message ) {}
9122     ${className}( char const * message )
9123       : SystemError( make_error_code( ${enumName}::${enumMemberName} ), message ) {}
9124   };
9125 ${leave})";
9126 
9127   std::string str;
9128   auto        enumIt = m_enums.find( "VkResult" );
9129   for ( auto const & value : enumIt->second.values )
9130   {
9131     if ( value.name.starts_with( "VK_ERROR" ) )
9132     {
9133       auto [enter, leave]   = generateProtection( getProtect( value ) );
9134       std::string valueName = generateEnumValueName( enumIt->first, value.name, false, m_tags );
9135       str += replaceWithMap( templateString,
9136                              { { "className", stripPrefix( valueName, "eError" ) + "Error" },
9137                                { "enter", enter },
9138                                { "enumName", stripPrefix( enumIt->first, "Vk" ) },
9139                                { "enumMemberName", valueName },
9140                                { "leave", leave } } );
9141     }
9142   }
9143   return str;
9144 }
9145 
generateReturnStatement(std::string const & commandName,CommandData const & commandData,std::string const & returnVariable,std::string const & returnType,std::string const & dataType,size_t initialSkipCount,size_t returnParam,CommandFlavourFlags flavourFlags,bool enumerating,bool raii) const9146 std::string VulkanHppGenerator::generateReturnStatement( std::string const & commandName,
9147                                                          CommandData const & commandData,
9148                                                          std::string const & returnVariable,
9149                                                          std::string const & returnType,
9150                                                          std::string const & dataType,
9151                                                          size_t              initialSkipCount,
9152                                                          size_t              returnParam,
9153                                                          CommandFlavourFlags flavourFlags,
9154                                                          bool                enumerating,
9155                                                          bool                raii ) const
9156 {
9157   bool unique = flavourFlags & CommandFlavourFlagBits::unique;
9158 
9159   std::string returnStatement;
9160   if ( commandData.returnType.starts_with( "Vk" ) )
9161   {
9162     if ( ( commandData.successCodes.size() == 1 ) || enumerating )
9163     {
9164       assert( commandData.successCodes[0] == "VK_SUCCESS" );
9165       if ( raii || commandData.errorCodes.empty() )
9166       {
9167         if ( !returnVariable.empty() )
9168         {
9169           returnStatement = "return " + returnVariable + ";";
9170         }
9171       }
9172       else
9173       {
9174         if ( returnVariable.empty() )
9175         {
9176           assert( !unique );
9177           returnStatement = "return createResultValueType( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ) );";
9178         }
9179         else if ( unique )
9180         {
9181           assert( returnParam != INVALID_INDEX );
9182           returnStatement = "return createResultValueType( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), ";
9183           if ( dataType.starts_with( "std::" ) )
9184           {
9185             returnStatement += "std::move( unique" + startUpperCase( returnVariable ) + " )";
9186           }
9187           else
9188           {
9189             returnStatement += "UniqueHandle<" + dataType + ", Dispatch>( " + returnVariable + ", " +
9190                                generateObjectDeleter( commandName, commandData, initialSkipCount, returnParam ) + " )";
9191           }
9192           returnStatement += " );";
9193         }
9194         else
9195         {
9196           returnStatement = "return createResultValueType( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), " + returnVariable + " );";
9197         }
9198       }
9199     }
9200     else
9201     {
9202       if ( returnVariable.empty() )
9203       {
9204         assert( !unique );
9205         returnStatement = "return static_cast<VULKAN_HPP_NAMESPACE::" + stripPrefix( commandData.returnType, "Vk" ) + ">( result );";
9206       }
9207       else if ( unique )
9208       {
9209         assert( returnParam != INVALID_INDEX );
9210         assert( returnType.starts_with( "ResultValue<" ) && returnType.ends_with( ">" ) );
9211         returnStatement = "return " + returnType + "( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), ";
9212         if ( dataType.starts_with( "std::" ) )
9213         {
9214           returnStatement += "std::move( unique" + startUpperCase( returnVariable ) + " )";
9215         }
9216         else
9217         {
9218           returnStatement += "UniqueHandle<" + dataType + ", Dispatch>( " + returnVariable + ", " +
9219                              generateObjectDeleter( commandName, commandData, initialSkipCount, returnParam ) + " )";
9220         }
9221         returnStatement += " );";
9222       }
9223       else
9224       {
9225         assert( returnType.starts_with( raii ? "std::pair<VULKAN_HPP_NAMESPACE::Result, " : "ResultValue<" ) && returnType.ends_with( ">" ) );
9226         returnStatement =
9227           "return " + ( raii ? "std::make_pair" : returnType ) + "( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), " + returnVariable + " );";
9228       }
9229     }
9230   }
9231   else
9232   {
9233     assert( !unique );
9234     if ( returnVariable.empty() )
9235     {
9236       if ( commandData.returnType != "void" )
9237       {
9238         returnStatement = "return result;";
9239       }
9240     }
9241     else
9242     {
9243       returnStatement = "return " + returnVariable + ";";
9244     }
9245   }
9246   return returnStatement;
9247 }
9248 
generateReturnType(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool raii,std::string const & dataType) const9249 std::string VulkanHppGenerator::generateReturnType( CommandData const &                       commandData,
9250                                                     std::vector<size_t> const &               returnParams,
9251                                                     std::map<size_t, VectorParamData> const & vectorParams,
9252                                                     CommandFlavourFlags                       flavourFlags,
9253                                                     bool                                      raii,
9254                                                     std::string const &                       dataType ) const
9255 {
9256   bool chained = flavourFlags & CommandFlavourFlagBits::chained;
9257   bool unique  = flavourFlags & CommandFlavourFlagBits::unique;
9258 
9259   std::string modifiedDataType = dataType;
9260   if ( chained )
9261   {
9262     assert( !unique );
9263     modifiedDataType = dataType.starts_with( "std::vector" )
9264                        ? ( std::string( "std::vector<StructureChain" ) + ( raii ? "" : ", StructureChainAllocator" ) + ">" )
9265                        : "StructureChain<X, Y, Z...>";
9266   }
9267   else if ( unique )
9268   {
9269     assert( !chained );
9270     assert( ( returnParams.size() == 1 ) && isHandleType( commandData.params[returnParams[0]].type.type ) );
9271     if ( dataType.starts_with( "std::vector" ) )
9272     {
9273       auto from = dataType.find( '<' ) + 1;
9274       assert( from != std::string::npos );
9275       auto to = dataType.find( '>', from );
9276       assert( to == dataType.length() - 1 );
9277       std::string type = dataType.substr( from, to - from );
9278       assert( type.starts_with( "VULKAN_HPP_NAMESPACE::" ) );
9279       modifiedDataType.replace( from, to - from, "UniqueHandle<" + type + ", Dispatch>, " + stripPrefix( type, "VULKAN_HPP_NAMESPACE::" ) + "Allocator" );
9280     }
9281     else
9282     {
9283       assert( !dataType.starts_with( "std::" ) );
9284       modifiedDataType = "UniqueHandle<" + dataType + ", Dispatch>";
9285     }
9286   }
9287 
9288   std::string returnType;
9289   if ( ( 1 < commandData.successCodes.size() ) && returnParams.empty() && !chained )
9290   {
9291     assert( ( commandData.returnType == "VkResult" ) && !unique );
9292     returnType = "VULKAN_HPP_NAMESPACE::Result";
9293   }
9294   else if ( ( commandData.returnType != "VkResult" ) && ( commandData.returnType != "void" ) )
9295   {
9296     assert( returnParams.empty() && !chained && !unique );
9297     if ( commandData.returnType.starts_with( "Vk" ) )
9298     {
9299       returnType = generateNamespacedType( commandData.returnType );
9300     }
9301     else
9302     {
9303       returnType = commandData.returnType;
9304     }
9305   }
9306   else if ( ( commandData.returnType == "void" ) ||
9307             ( ( commandData.returnType == "VkResult" ) && ( commandData.successCodes.size() == 1 ) && ( commandData.errorCodes.empty() || raii ) ) )
9308   {
9309     assert( !unique );
9310     assert( ( commandData.returnType != "void" ) || ( returnParams.size() <= 2 ) );
9311     returnType = modifiedDataType;
9312   }
9313   else
9314   {
9315     assert( commandData.returnType == "VkResult" );
9316     assert( !commandData.successCodes.empty() && ( commandData.successCodes[0] == "VK_SUCCESS" ) );
9317     if ( ( 1 < commandData.successCodes.size() ) && ( ( returnParams.size() == 1 ) || ( ( returnParams.size() == 2 ) && vectorParams.empty() ) ) )
9318     {
9319       assert( !commandData.errorCodes.empty() );
9320       returnType = ( raii ? "std::pair<VULKAN_HPP_NAMESPACE::Result, " : "ResultValue<" ) + modifiedDataType + ">";
9321     }
9322     else
9323     {
9324       assert(
9325         ( ( commandData.successCodes.size() == 1 ) || ( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[1] == "VK_INCOMPLETE" ) ) ) &&
9326         ( returnParams.size() <= 3 ) );
9327       returnType = raii ? modifiedDataType : ( "typename ResultValueType<" + modifiedDataType + ">::type" );
9328     }
9329   }
9330   return returnType;
9331 }
9332 
generateReturnVariable(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags) const9333 std::string VulkanHppGenerator::generateReturnVariable( CommandData const &                       commandData,
9334                                                         std::vector<size_t> const &               returnParams,
9335                                                         std::map<size_t, VectorParamData> const & vectorParams,
9336                                                         CommandFlavourFlags                       flavourFlags ) const
9337 {
9338   bool chained  = flavourFlags & CommandFlavourFlagBits::chained;
9339   bool singular = flavourFlags & CommandFlavourFlagBits::singular;
9340 
9341   std::string returnVariable;
9342   switch ( returnParams.size() )
9343   {
9344     case 0: break;  // no return variable
9345     case 1:
9346       if ( chained )
9347       {
9348         returnVariable = "structureChain";
9349       }
9350       else
9351       {
9352         returnVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
9353         if ( singular )
9354         {
9355           returnVariable = stripPluralS( returnVariable, m_tags );
9356         }
9357       }
9358       break;
9359     case 2:
9360       if ( chained )
9361       {
9362         returnVariable = "structureChains";
9363       }
9364       else
9365       {
9366         auto vectorParamIt = vectorParams.find( returnParams[1] );
9367         if ( vectorParamIt == vectorParams.end() )
9368         {  // the return variable is simply named "data", and holds the multi-return value stuff
9369           returnVariable = "data";
9370         }
9371         else
9372         {
9373           assert( vectorParamIt->second.lenParam == returnParams[0] );
9374           assert( !singular );
9375           returnVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
9376         }
9377       }
9378       break;
9379     case 3:
9380       assert( !chained && !singular );
9381       assert( ( vectorParams.size() == 2 ) && ( vectorParams.begin()->first == returnParams[1] ) &&
9382               ( vectorParams.begin()->second.lenParam == returnParams[0] ) && ( std::next( vectorParams.begin() )->first == returnParams[2] ) &&
9383               ( std::next( vectorParams.begin() )->second.lenParam == returnParams[0] ) );
9384       returnVariable = "data";
9385       break;
9386   }
9387   return returnVariable;
9388 }
9389 
generateSizeCheck(std::vector<std::vector<MemberData>::const_iterator> const & arrayIts,std::string const & structName,bool mutualExclusiveLens) const9390 std::string VulkanHppGenerator::generateSizeCheck( std::vector<std::vector<MemberData>::const_iterator> const & arrayIts,
9391                                                    std::string const &                                          structName,
9392                                                    bool                                                         mutualExclusiveLens ) const
9393 {
9394   std::string sizeCheck;
9395   if ( 1 < arrayIts.size() )
9396   {
9397     static const std::string throwTextTemplate = R"(      if ( ${throwCheck} )
9398       {
9399         throw LogicError( VULKAN_HPP_NAMESPACE_STRING"::${structName}::${structName}: ${throwCheck}" );
9400       }
9401 )";
9402 
9403     std::string assertionText, throwText;
9404     if ( mutualExclusiveLens )
9405     {
9406       // exactly one of the arrays has to be non-empty
9407       std::string sum;
9408       for ( auto it : arrayIts )
9409       {
9410         sum += "!" + startLowerCase( stripPrefix( it->name, "p" ) ) + "_.empty() + ";
9411       }
9412       sum.resize( sum.size() - 3 );
9413       assertionText += "      VULKAN_HPP_ASSERT( ( " + sum + " ) <= 1);\n";
9414       throwText += replaceWithMap( throwTextTemplate, { { "structName", structName }, { "throwCheck", "1 < ( " + sum + " )" } } );
9415     }
9416     else
9417     {
9418       for ( size_t first = 0; first + 1 < arrayIts.size(); ++first )
9419       {
9420         assert( arrayIts[first]->name.starts_with( "p" ) );
9421         std::string firstName = startLowerCase( stripPrefix( arrayIts[first]->name, "p" ) ) + "_";
9422         for ( auto second = first + 1; second < arrayIts.size(); ++second )
9423         {
9424           assert( arrayIts[second]->name.starts_with( "p" ) );
9425           std::string secondName     = startLowerCase( stripPrefix( arrayIts[second]->name, "p" ) ) + "_";
9426           std::string assertionCheck = firstName + ".size() == " + secondName + ".size()";
9427           std::string throwCheck     = firstName + ".size() != " + secondName + ".size()";
9428           if ( ( !arrayIts[first]->optional.empty() && arrayIts[first]->optional.front() ) ||
9429                ( !arrayIts[second]->optional.empty() && arrayIts[second]->optional.front() ) )
9430           {
9431             assertionCheck = "( " + assertionCheck + " )";
9432             throwCheck     = "( " + throwCheck + " )";
9433             if ( !arrayIts[second]->optional.empty() && arrayIts[second]->optional.front() )
9434             {
9435               assertionCheck = secondName + ".empty() || " + assertionCheck;
9436               throwCheck     = "!" + secondName + ".empty() && " + throwCheck;
9437             }
9438             if ( !arrayIts[first]->optional.empty() && arrayIts[first]->optional.front() )
9439             {
9440               assertionCheck = firstName + ".empty() || " + assertionCheck;
9441               throwCheck     = "!" + firstName + ".empty() && " + throwCheck;
9442             }
9443           }
9444           assertionText += "      VULKAN_HPP_ASSERT( " + assertionCheck + " );\n";
9445           throwText += replaceWithMap( throwTextTemplate, { { "structName", structName }, { "throwCheck", throwCheck } } );
9446         }
9447       }
9448     }
9449     sizeCheck += "\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n" + assertionText + "#else\n" + throwText + "#endif /*VULKAN_HPP_NO_EXCEPTIONS*/\n" + "    ";
9450   }
9451   return sizeCheck;
9452 }
9453 
generateStaticAssertions() const9454 std::string VulkanHppGenerator::generateStaticAssertions() const
9455 {
9456   std::string staticAssertions;
9457   for ( auto const & feature : m_features )
9458   {
9459     staticAssertions += generateStaticAssertions( feature.second.requireData, feature.first );
9460   }
9461   for ( auto const & extIt : m_extensionsByNumber )
9462   {
9463     staticAssertions += generateStaticAssertions( extIt.second->second.requireData, extIt.second->first );
9464   }
9465   return staticAssertions;
9466 }
9467 
generateStaticAssertions(std::vector<RequireData> const & requireData,std::string const & title) const9468 std::string VulkanHppGenerator::generateStaticAssertions( std::vector<RequireData> const & requireData, std::string const & title ) const
9469 {
9470   std::string str;
9471   for ( auto const & require : requireData )
9472   {
9473     for ( auto const & type : require.types )
9474     {
9475       auto handleIt = m_handles.find( type );
9476       if ( handleIt != m_handles.end() )
9477       {
9478         std::string const assertionTemplate = R"(
9479 VULKAN_HPP_STATIC_ASSERT( sizeof( VULKAN_HPP_NAMESPACE::${className} ) == sizeof( Vk${className} ), "handle and wrapper have different size!" );
9480 VULKAN_HPP_STATIC_ASSERT( std::is_nothrow_move_constructible<VULKAN_HPP_NAMESPACE::${className}>::value, "${className} is not nothrow_move_constructible!" );
9481 )";
9482         str += replaceWithMap( assertionTemplate, { { "className", stripPrefix( handleIt->first, "Vk" ) } } );
9483       }
9484       else
9485       {
9486         auto structIt = m_structures.find( type );
9487         if ( structIt != m_structures.end() )
9488         {
9489           std::string const assertionTemplate = R"(
9490 VULKAN_HPP_STATIC_ASSERT( sizeof( VULKAN_HPP_NAMESPACE::${structureType} ) == sizeof( Vk${structureType} ), "struct and wrapper have different size!" );
9491 VULKAN_HPP_STATIC_ASSERT( std::is_standard_layout<VULKAN_HPP_NAMESPACE::${structureType}>::value, "struct wrapper is not a standard layout!" );
9492 VULKAN_HPP_STATIC_ASSERT( std::is_nothrow_move_constructible<VULKAN_HPP_NAMESPACE::${structureType}>::value, "${structureType} is not nothrow_move_constructible!" );
9493 )";
9494           str += replaceWithMap( assertionTemplate, { { "structureType", stripPrefix( structIt->first, "Vk" ) } } );
9495         }
9496       }
9497     }
9498   }
9499   return addTitleAndProtection( title, str );
9500 }
9501 
generateStruct(std::pair<std::string,StructureData> const & structure,std::set<std::string> & listedStructs) const9502 std::string VulkanHppGenerator::generateStruct( std::pair<std::string, StructureData> const & structure, std::set<std::string> & listedStructs ) const
9503 {
9504   assert( listedStructs.find( structure.first ) == listedStructs.end() );
9505 
9506   std::string str;
9507   for ( auto const & member : structure.second.members )
9508   {
9509     auto structIt = m_structures.find( member.type.type );
9510     if ( ( structIt != m_structures.end() ) && ( structure.first != member.type.type ) && ( listedStructs.find( member.type.type ) == listedStructs.end() ) )
9511     {
9512       str += generateStruct( *structIt, listedStructs );
9513     }
9514   }
9515 
9516   if ( !structure.second.subStruct.empty() )
9517   {
9518     auto structureIt = m_structures.find( structure.second.subStruct );
9519     if ( ( structureIt != m_structures.end() ) && ( listedStructs.find( structureIt->first ) == listedStructs.end() ) )
9520     {
9521       str += generateStruct( *structureIt, listedStructs );
9522     }
9523   }
9524 
9525   if ( structure.second.isUnion )
9526   {
9527     str += generateUnion( structure );
9528   }
9529   else
9530   {
9531     str += generateStructure( structure );
9532   }
9533 
9534   listedStructs.insert( structure.first );
9535   return str;
9536 }
9537 
generateStructCompareOperators(std::pair<std::string,StructureData> const & structData) const9538 std::string VulkanHppGenerator::generateStructCompareOperators( std::pair<std::string, StructureData> const & structData ) const
9539 {
9540   static const std::set<std::string> simpleTypes = { "char",   "double",  "DWORD",    "float",    "HANDLE",  "HINSTANCE", "HMONITOR",
9541                                                      "HWND",   "int",     "int8_t",   "int16_t",  "int32_t", "int64_t",   "LPCWSTR",
9542                                                      "size_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t" };
9543   // two structs are compared by comparing each of the elements
9544   std::string compareMembers, spaceshipMembers;
9545   std::string intro             = "";
9546   bool        nonDefaultCompare = false;
9547   std::string spaceshipOrdering = containsFloatingPoints( structData.second.members ) ? "std::partial_ordering" : "std::strong_ordering";
9548   for ( size_t i = 0; i < structData.second.members.size(); i++ )
9549   {
9550     MemberData const & member = structData.second.members[i];
9551     auto               typeIt = m_types.find( member.type.type );
9552     assert( typeIt != m_types.end() );
9553     if ( ( typeIt->second.category == TypeCategory::Requires ) && member.type.postfix.empty() && ( simpleTypes.find( member.type.type ) == simpleTypes.end() ) )
9554     {
9555       nonDefaultCompare = true;
9556       // this type might support operator==() or operator<=>()... that is, use memcmp
9557       compareMembers += intro + "( memcmp( &" + member.name + ", &rhs." + member.name + ", sizeof( " + member.type.type + " ) ) == 0 )";
9558 
9559       static const std::string spaceshipMemberTemplate =
9560         R"(      if ( auto cmp = memcmp( &${name}, &rhs.${name}, sizeof( ${type} ) ); cmp != 0 )
9561         return ( cmp < 0 ) ? ${ordering}::less : ${ordering}::greater;
9562 )";
9563       spaceshipMembers +=
9564         replaceWithMap( spaceshipMemberTemplate, { { "name", member.name }, { "ordering", spaceshipOrdering }, { "type", member.type.type } } );
9565     }
9566     else if ( member.type.type == "char" && !member.len.empty() )
9567     {
9568       // compare null-terminated strings
9569       nonDefaultCompare = true;
9570       assert( member.len.size() < 3 );
9571       if ( member.len.size() == 1 )
9572       {
9573         assert( member.len[0] == "null-terminated" );
9574         compareMembers += intro + "( ( " + member.name + " == rhs." + member.name + " ) || ( strcmp( " + member.name + ", rhs." + member.name + " ) == 0 ) )";
9575 
9576         static const std::string spaceshipMemberTemplate =
9577           R"(     if ( ${name} != rhs.${name} )
9578         if ( auto cmp = strcmp( ${name}, rhs.${name} ); cmp != 0 )
9579           return ( cmp < 0 ) ? ${ordering}::less : ${ordering}::greater;
9580 )";
9581         spaceshipMembers += replaceWithMap( spaceshipMemberTemplate, { { "name", member.name }, { "ordering", spaceshipOrdering } } );
9582       }
9583       else
9584       {
9585         assert( member.len[1] == "null-terminated" );
9586         assert( ( member.type.prefix == "const" ) && ( member.type.postfix == "* const *" ) );
9587         static const std::string compareMemberTemplate =
9588           R"(std::equal( ${name}, ${name} + ${count}, rhs.${name}, []( char const * left, char const * right ) { return ( left == right ) || ( strcmp( left, right ) == 0 ); } ))";
9589         compareMembers += intro + replaceWithMap( compareMemberTemplate, { { "count", member.len[0] }, { "name", member.name } } );
9590 
9591         static const std::string spaceshipMemberTemplate = R"(      for ( size_t i = 0; i < ${count}; ++i )
9592       {
9593         if ( ${name}[i] != rhs.${name}[i] )
9594           if ( auto cmp = strcmp( ${name}[i], rhs.${name}[i] ); cmp != 0 )
9595             return cmp < 0 ? ${ordering}::less : ${ordering}::greater;
9596       }
9597 )";
9598         spaceshipMembers +=
9599           replaceWithMap( spaceshipMemberTemplate, { { "count", member.len[0] }, { "name", member.name }, { "ordering", spaceshipOrdering } } );
9600       }
9601     }
9602     else
9603     {
9604       // for all others, we use the operator== of that type
9605       compareMembers += intro + "( " + member.name + " == rhs." + member.name + " )";
9606       spaceshipMembers += "      if ( auto cmp = " + member.name + " <=> rhs." + member.name + "; cmp != 0 ) return cmp;\n";
9607     }
9608     intro = "\n          && ";
9609   }
9610 
9611   std::string structName = stripPrefix( structData.first, "Vk" );
9612 
9613   std::string compareBody, spaceshipOperator, spaceshipOperatorIf, spaceshipOperatorElse, spaceshipOperatorEndif;
9614   if ( nonDefaultCompare )
9615   {
9616     compareBody = "      return " + compareMembers + ";";
9617 
9618     if ( !containsFuncPointer( structData.first ) )
9619     {
9620       static const std::string spaceshipOperatorTemplate =
9621         R"(    ${ordering} operator<=>( ${name} const & rhs ) const VULKAN_HPP_NOEXCEPT
9622     {
9623 ${spaceshipMembers}
9624       return ${ordering}::equivalent;
9625     })";
9626       spaceshipOperatorIf = "#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)";
9627       spaceshipOperator =
9628         replaceWithMap( spaceshipOperatorTemplate, { { "name", structName }, { "ordering", spaceshipOrdering }, { "spaceshipMembers", spaceshipMembers } } );
9629       spaceshipOperatorElse  = "#endif\n";
9630       spaceshipOperatorEndif = "";
9631     }
9632   }
9633   else
9634   {
9635     // use reflection only if VULKAN_HPP_USE_REFLECT is defined
9636     static const std::string compareBodyTemplate = R"(#if defined( VULKAN_HPP_USE_REFLECT )
9637       return this->reflect() == rhs.reflect();
9638 #else
9639       return ${compareMembers};
9640 #endif)";
9641     compareBody                                  = replaceWithMap( compareBodyTemplate, { { "compareMembers", compareMembers } } );
9642 
9643     if ( !containsFuncPointer( structData.first ) )
9644     {
9645       spaceshipOperatorIf    = "#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)";
9646       spaceshipOperator      = "auto operator<=>( " + structName + " const & ) const = default;";
9647       spaceshipOperatorElse  = "#else";
9648       spaceshipOperatorEndif = "#endif\n";
9649     }
9650   }
9651 
9652   static const std::string compareTemplate = R"(
9653 ${spaceshipOperatorIf}
9654 ${spaceshipOperator}
9655 ${spaceshipOperatorElse}
9656     bool operator==( ${name} const & rhs ) const VULKAN_HPP_NOEXCEPT
9657     {
9658 ${compareBody}
9659     }
9660 
9661     bool operator!=( ${name} const & rhs ) const VULKAN_HPP_NOEXCEPT
9662     {
9663       return !operator==( rhs );
9664     }
9665 ${spaceshipOperatorEndif})";
9666 
9667   return replaceWithMap( compareTemplate,
9668                          { { "name", structName },
9669                            { "compareBody", compareBody },
9670                            { "spaceshipOperator", spaceshipOperator },
9671                            { "spaceshipOperatorElse", spaceshipOperatorElse },
9672                            { "spaceshipOperatorEndif", spaceshipOperatorEndif },
9673                            { "spaceshipOperatorIf", spaceshipOperatorIf } } );
9674 }
9675 
generateStructConstructors(std::pair<std::string,StructureData> const & structData) const9676 std::string VulkanHppGenerator::generateStructConstructors( std::pair<std::string, StructureData> const & structData ) const
9677 {
9678   // the constructor with all the elements as arguments, with defaults
9679   // and the simple copy constructor from the corresponding vulkan structure
9680   static const std::string constructors = R"(${constexpr}${structName}(${arguments}) VULKAN_HPP_NOEXCEPT
9681     ${initializers}
9682     {}
9683 
9684     ${constexpr}${structName}( ${structName} const & rhs ) VULKAN_HPP_NOEXCEPT = default;
9685 
9686     ${structName}( Vk${structName} const & rhs ) VULKAN_HPP_NOEXCEPT
9687       : ${structName}( *reinterpret_cast<${structName} const *>( &rhs ) )
9688     {}
9689 )";
9690 
9691   std::string arguments, initializers;
9692   bool        listedArgument = false;
9693   bool        firstArgument  = true;
9694   for ( auto const & member : structData.second.members )
9695   {
9696     // gather the arguments
9697     std::string argument = generateStructConstructorArgument( listedArgument, member, true );
9698     if ( !argument.empty() )
9699     {
9700       listedArgument = true;
9701       arguments += argument;
9702     }
9703 
9704     // gather the initializers; skip members with exactly one legal value
9705     if ( member.value.empty() )
9706     {
9707       initializers += std::string( firstArgument ? ": " : ", " ) + member.name + "( " + member.name + "_ )";
9708       firstArgument = false;
9709     }
9710   }
9711   auto pNextIt = std::find_if( structData.second.members.begin(), structData.second.members.end(), []( MemberData const & md ) { return md.name == "pNext"; } );
9712   if ( pNextIt != structData.second.members.end() )
9713   {
9714     // add pNext as a last optional argument to the constructor
9715     arguments += std::string( listedArgument ? ", " : "" ) + pNextIt->type.compose( "VULKAN_HPP_NAMESPACE" ) + " pNext_ = nullptr";
9716   }
9717 
9718   std::string str = replaceWithMap( constructors,
9719                                     { { "arguments", arguments },
9720                                       { "constexpr", generateConstexprString( structData.first ) },
9721                                       { "initializers", initializers },
9722                                       { "structName", stripPrefix( structData.first, "Vk" ) } } );
9723 
9724   str += generateStructConstructorsEnhanced( structData );
9725   return str;
9726 }
9727 
generateStructConstructorsEnhanced(std::pair<std::string,StructureData> const & structData) const9728 std::string VulkanHppGenerator::generateStructConstructorsEnhanced( std::pair<std::string, StructureData> const & structData ) const
9729 {
9730   if ( std::find_if( structData.second.members.begin(),
9731                      structData.second.members.end(),
9732                      [this, &structData]( MemberData const & md ) { return hasLen( structData.second.members, md ); } ) != structData.second.members.end() )
9733   {
9734     // map from len-members to all the array members using that len
9735     std::map<std::vector<MemberData>::const_iterator, std::vector<std::vector<MemberData>::const_iterator>> lenIts;
9736     for ( auto mit = structData.second.members.begin(); mit != structData.second.members.end(); ++mit )
9737     {
9738       if ( hasLen( structData.second.members, *mit ) )
9739       {
9740         std::string lenName = ( mit->len.front() == "codeSize / 4" ) ? "codeSize" : mit->len.front();
9741         auto        lenIt   = findStructMemberIt( lenName, structData.second.members );
9742         assert( lenIt != mit );
9743         lenIts[lenIt].push_back( mit );
9744       }
9745     }
9746 
9747     std::string arguments, initializers;
9748     bool        listedArgument = false;
9749     bool        firstArgument  = true;
9750     bool        arrayListed    = false;
9751     std::string templateHeader, sizeChecks;
9752     for ( auto mit = structData.second.members.begin(); mit != structData.second.members.end(); ++mit )
9753     {
9754       // gather the initializers
9755       if ( mit->name == "pNext" )  // for pNext, we just get the initializer... the argument is added at the end
9756       {
9757         initializers += std::string( firstArgument ? ":" : "," ) + " pNext( pNext_ )";
9758         firstArgument = false;
9759       }
9760       else if ( mit->value.empty() )  // skip constant members
9761       {
9762         auto litit = lenIts.find( mit );
9763         if ( litit != lenIts.end() )
9764         {
9765           // len arguments just have an initalizer, from the ArrayProxyNoTemporaries size
9766           initializers +=
9767             ( firstArgument ? ": " : ", " ) + mit->name + "( " + generateLenInitializer( mit, litit, structData.second.mutualExclusiveLens ) + " )";
9768           sizeChecks += generateSizeCheck( litit->second, stripPrefix( structData.first, "Vk" ), structData.second.mutualExclusiveLens );
9769         }
9770         else if ( hasLen( structData.second.members, *mit ) )
9771         {
9772           assert( mit->name.starts_with( "p" ) );
9773           std::string argumentName = startLowerCase( stripPrefix( mit->name, "p" ) ) + "_";
9774 
9775           assert( mit->type.postfix.ends_with( "*" ) );
9776           std::string argumentType = trimEnd( stripPostfix( mit->type.compose( "VULKAN_HPP_NAMESPACE" ), "*" ) );
9777           if ( ( mit->type.type == "void" ) && ( argumentType.find( '*' ) == std::string::npos ) )
9778           {
9779             // the argument after stripping one pointer is just void
9780             assert( templateHeader.empty() );
9781             templateHeader = "    template <typename T>\n";
9782 
9783             size_t pos = argumentType.find( "void" );
9784             assert( pos != std::string::npos );
9785             argumentType.replace( pos, strlen( "void" ), "T" );
9786           }
9787 
9788           arguments += listedArgument ? ", " : "";
9789           arguments += "VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<" + argumentType + "> const & " + argumentName;
9790           if ( arrayListed )
9791           {
9792             arguments += " = {}";
9793           }
9794           listedArgument = true;
9795           arrayListed    = true;
9796 
9797           initializers += ( firstArgument ? ": " : ", " ) + mit->name + "( " + argumentName + ".data() )";
9798         }
9799         else
9800         {
9801           std::string argument = generateStructConstructorArgument( listedArgument, *mit, arrayListed );
9802           if ( !argument.empty() )
9803           {
9804             listedArgument = true;
9805             arguments += argument;
9806           }
9807           initializers += ( firstArgument ? ": " : ", " ) + mit->name + "( " + mit->name + "_ )";
9808         }
9809         firstArgument = false;
9810       }
9811     }
9812 
9813     auto pNextIt =
9814       std::find_if( structData.second.members.begin(), structData.second.members.end(), []( MemberData const & md ) { return md.name == "pNext"; } );
9815     if ( pNextIt != structData.second.members.end() )
9816     {
9817       // add pNext as a last optional argument to the constructor
9818       arguments += std::string( listedArgument ? ", " : "" ) + pNextIt->type.compose( "VULKAN_HPP_NAMESPACE" ) + " pNext_ = nullptr";
9819     }
9820 
9821     static const std::string constructorTemplate = R"(
9822 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
9823 ${templateHeader}    ${structName}( ${arguments} )
9824     ${initializers}
9825     {${sizeChecks}}
9826 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
9827 )";
9828 
9829     return replaceWithMap( constructorTemplate,
9830                            { { "arguments", arguments },
9831                              { "initializers", initializers },
9832                              { "sizeChecks", sizeChecks },
9833                              { "structName", stripPrefix( structData.first, "Vk" ) },
9834                              { "templateHeader", templateHeader } } );
9835   }
9836   return "";
9837 }
9838 
generateStructConstructorArgument(bool listedArgument,MemberData const & memberData,bool withDefault) const9839 std::string VulkanHppGenerator::generateStructConstructorArgument( bool listedArgument, MemberData const & memberData, bool withDefault ) const
9840 {
9841   // skip members 'pNext' and members with a specified value, as they are never explicitly set
9842   std::string str;
9843   if ( ( memberData.name != "pNext" ) && memberData.value.empty() )
9844   {
9845     str += ( listedArgument ? ( ", " ) : "" );
9846     if ( memberData.arraySizes.empty() )
9847     {
9848       str += memberData.type.compose( "VULKAN_HPP_NAMESPACE" ) + " ";
9849     }
9850     else
9851     {
9852       str += generateStandardArray( memberData.type.compose( "VULKAN_HPP_NAMESPACE" ), memberData.arraySizes ) + " const & ";
9853     }
9854     str += memberData.name + "_";
9855 
9856     if ( withDefault )
9857     {
9858       str += " = ";
9859       auto enumIt = m_enums.find( memberData.type.type );
9860       if ( enumIt != m_enums.end() && memberData.type.postfix.empty() )
9861       {
9862         str += generateEnumInitializer( memberData.type, memberData.arraySizes, enumIt->second.values, enumIt->second.isBitmask );
9863       }
9864       else
9865       {
9866         assert( memberData.value.empty() );
9867         // all the rest can be initialized with just {}
9868         str += "{}";
9869       }
9870     }
9871   }
9872   return str;
9873 }
9874 
generateStructHashStructure(std::pair<std::string,StructureData> const & structure,std::set<std::string> & listedStructs) const9875 std::string VulkanHppGenerator::generateStructHashStructure( std::pair<std::string, StructureData> const & structure,
9876                                                              std::set<std::string> &                       listedStructs ) const
9877 {
9878   assert( listedStructs.find( structure.first ) == listedStructs.end() );
9879 
9880   std::string str;
9881   for ( auto const & member : structure.second.members )
9882   {
9883     auto structIt = m_structures.find( member.type.type );
9884     if ( ( structIt != m_structures.end() ) && ( structure.first != member.type.type ) && ( listedStructs.find( member.type.type ) == listedStructs.end() ) )
9885     {
9886       str += generateStructHashStructure( *structIt, listedStructs );
9887     }
9888   }
9889 
9890   if ( !containsUnion( structure.first ) )
9891   {
9892     static const std::string hashTemplate = R"(
9893   ${enter}template <> struct hash<VULKAN_HPP_NAMESPACE::${structureType}>
9894   {
9895     std::size_t operator()(VULKAN_HPP_NAMESPACE::${structureType} const & ${structureName}) const VULKAN_HPP_NOEXCEPT
9896     {
9897       std::size_t seed = 0;
9898 ${hashSum}
9899       return seed;
9900     }
9901   };
9902 ${leave})";
9903 
9904     auto [enter, leave] =
9905       generateProtection( m_structureAliasesInverse.find( structure.first ) == m_structureAliasesInverse.end() ? getProtectFromType( structure.first ) : "" );
9906 
9907     std::string structureType = stripPrefix( structure.first, "Vk" );
9908     std::string structureName = startLowerCase( structureType );
9909     str += replaceWithMap( hashTemplate,
9910                            { { "enter", enter },
9911                              { "hashSum", generateStructHashSum( structureName, structure.second.members ) },
9912                              { "leave", leave },
9913                              { "structureName", structureName },
9914                              { "structureType", structureType } } );
9915   }
9916 
9917   listedStructs.insert( structure.first );
9918   return str;
9919 }
9920 
generateStructHashStructures() const9921 std::string VulkanHppGenerator::generateStructHashStructures() const
9922 {
9923   const std::string hashesTemplate = R"(
9924 #if 14 <= VULKAN_HPP_CPP_VERSION
9925   //======================================
9926   //=== HASH structures for structures ===
9927   //======================================
9928 
9929 #  if !defined( VULKAN_HPP_HASH_COMBINE )
9930 #    define VULKAN_HPP_HASH_COMBINE( seed, value ) \
9931       seed ^= std::hash<std::decay<decltype( value )>::type>{}( value ) + 0x9e3779b9 + ( seed << 6 ) + ( seed >> 2 )
9932 #  endif
9933 
9934 ${hashes}
9935 #endif    // 14 <= VULKAN_HPP_CPP_VERSION
9936 )";
9937 
9938   // Note reordering structs or handles by features and extensions is not possible!
9939   std::set<std::string> listedStructs;
9940   std::string           hashes;
9941   for ( auto const & structure : m_structures )
9942   {
9943     if ( listedStructs.find( structure.first ) == listedStructs.end() )
9944     {
9945       hashes += generateStructHashStructure( structure, listedStructs );
9946     }
9947   }
9948   return replaceWithMap( hashesTemplate, { { "hashes", hashes } } );
9949 }
9950 
generateStructHashSum(std::string const & structName,std::vector<MemberData> const & members) const9951 std::string VulkanHppGenerator::generateStructHashSum( std::string const & structName, std::vector<MemberData> const & members ) const
9952 {
9953   std::string hashSum;
9954   for ( auto const & member : members )
9955   {
9956     if ( !member.arraySizes.empty() )
9957     {
9958       assert( member.arraySizes.size() < 3 );
9959       hashSum += "    for ( size_t i = 0; i < " + member.arraySizes[0] + "; ++i )\n";
9960       hashSum += "    {\n";
9961       if ( member.arraySizes.size() == 1 )
9962       {
9963         hashSum += "      VULKAN_HPP_HASH_COMBINE( seed, " + structName + "." + member.name + "[i] );\n";
9964       }
9965       else
9966       {
9967         hashSum += "      for ( size_t j=0; j < " + member.arraySizes[1] + "; ++j )\n";
9968         hashSum += "      {\n";
9969         hashSum += "        VULKAN_HPP_HASH_COMBINE( seed, " + structName + "." + member.name + "[i][j] );\n";
9970         hashSum += "      }\n";
9971       }
9972       hashSum += "    }\n";
9973     }
9974     else if ( member.type.type == "char" && !member.len.empty() )
9975     {
9976       assert( member.len.size() < 3 );
9977       if ( member.len.size() == 1 )
9978       {
9979         assert( member.len[0] == "null-terminated" );
9980         hashSum += "    for ( const char* p = " + structName + "." + member.name + "; *p != '\\0'; ++p )\n";
9981         hashSum += "    {\n";
9982         hashSum += "      VULKAN_HPP_HASH_COMBINE( seed, *p );\n";
9983         hashSum += "    }\n";
9984       }
9985       else
9986       {
9987         assert( member.len[1] == "null-terminated" );
9988         hashSum += "    for ( size_t i = 0; i < " + structName + "." + member.len[0] + "; ++i )\n";
9989         hashSum += "    {\n";
9990         hashSum += "        for ( const char* p = " + structName + "." + member.name + "[i]; *p != '\\0'; ++p )\n";
9991         hashSum += "        {\n";
9992         hashSum += "          VULKAN_HPP_HASH_COMBINE( seed, *p );\n";
9993         hashSum += "        }\n";
9994         hashSum += "    }\n";
9995       }
9996     }
9997     else
9998     {
9999       hashSum += "    VULKAN_HPP_HASH_COMBINE( seed, " + structName + "." + member.name + " );\n";
10000     }
10001   }
10002   assert( !hashSum.empty() );
10003   return hashSum.substr( 0, hashSum.size() - 1 );
10004 }
10005 
generateStructs() const10006 std::string VulkanHppGenerator::generateStructs() const
10007 {
10008   const std::string structsTemplate = R"(
10009   //===============
10010   //=== STRUCTS ===
10011   //===============
10012 
10013 ${structs}
10014 )";
10015 
10016   // Note reordering structs or handles by features and extensions is not possible!
10017   std::set<std::string> listedStructs;
10018   std::string           structs;
10019   for ( auto const & structure : m_structures )
10020   {
10021     if ( listedStructs.find( structure.first ) == listedStructs.end() )
10022     {
10023       structs += generateStruct( structure, listedStructs );
10024     }
10025   }
10026   return replaceWithMap( structsTemplate, { { "structs", structs } } );
10027 }
10028 
generateStructure(std::pair<std::string,StructureData> const & structure) const10029 std::string VulkanHppGenerator::generateStructure( std::pair<std::string, StructureData> const & structure ) const
10030 {
10031   auto [enter, leave] =
10032     generateProtection( m_structureAliasesInverse.find( structure.first ) == m_structureAliasesInverse.end() ? getProtectFromType( structure.first ) : "" );
10033 
10034   std::string str = "\n" + enter;
10035 
10036   static const std::string constructorsTemplate = R"(
10037 #if !defined( VULKAN_HPP_NO_STRUCT_CONSTRUCTORS )
10038 ${constructors}
10039 ${subConstructors}
10040     ${structName} & operator=( ${structName} const & rhs ) VULKAN_HPP_NOEXCEPT = default;
10041 #endif /*VULKAN_HPP_NO_STRUCT_CONSTRUCTORS*/
10042 
10043     ${structName} & operator=( Vk${structName} const & rhs ) VULKAN_HPP_NOEXCEPT
10044     {
10045       *this = *reinterpret_cast<VULKAN_HPP_NAMESPACE::${structName} const *>( &rhs );
10046       return *this;
10047     }
10048 )";
10049 
10050   std::string constructorsAndSetters = replaceWithMap( constructorsTemplate,
10051                                                        { { "constructors", generateStructConstructors( structure ) },
10052                                                          { "structName", stripPrefix( structure.first, "Vk" ) },
10053                                                          { "subConstructors", generateStructSubConstructor( structure ) } } );
10054 
10055   if ( !structure.second.returnedOnly )
10056   {
10057     // only structs that are not returnedOnly get setters!
10058     constructorsAndSetters += "\n#if !defined( VULKAN_HPP_NO_STRUCT_SETTERS )";
10059     for ( size_t i = 0; i < structure.second.members.size(); i++ )
10060     {
10061       constructorsAndSetters += generateStructSetter( stripPrefix( structure.first, "Vk" ), structure.second.members, i );
10062     }
10063     constructorsAndSetters += "#endif /*VULKAN_HPP_NO_STRUCT_SETTERS*/\n";
10064   }
10065 
10066   std::string structureType = stripPrefix( structure.first, "Vk" );
10067   // the member variables
10068   std::string members, memberNames, memberTypes, sTypeValue;
10069   std::tie( members, memberNames, memberTypes, sTypeValue ) = generateStructMembers( structure );
10070 
10071   // reflect is meaningfull for structs only, filter out unions
10072   std::string reflect;
10073   if ( !structure.second.isUnion )
10074   {
10075     // use reflection only if VULKAN_HPP_USE_REFLECT is defined
10076     static const std::string reflectTemplate = R"(
10077 #if defined( VULKAN_HPP_USE_REFLECT )
10078 #if 14 <= VULKAN_HPP_CPP_VERSION
10079     auto
10080 #else
10081     std::tuple<${memberTypes}>
10082 #endif
10083       reflect() const VULKAN_HPP_NOEXCEPT
10084     {
10085       return std::tie( ${memberNames} );
10086     }
10087 #endif
10088 )";
10089 
10090     reflect = replaceWithMap( reflectTemplate, { { "memberNames", memberNames }, { "memberTypes", memberTypes } } );
10091   }
10092 
10093   // operator==() and operator!=()
10094   // only structs without a union as a member can have a meaningfull == and != operation; we filter them out
10095   std::string compareOperators;
10096   if ( !containsUnion( structure.first ) )
10097   {
10098     compareOperators += generateStructCompareOperators( structure );
10099   }
10100 
10101   static const std::string structureTemplate = R"(  struct ${structureType}
10102   {
10103     using NativeType = Vk${structureType};
10104 
10105 ${allowDuplicate}
10106 ${typeValue}
10107 ${constructorsAndSetters}
10108 
10109     operator Vk${structureType} const &() const VULKAN_HPP_NOEXCEPT
10110     {
10111       return *reinterpret_cast<const Vk${structureType}*>( this );
10112     }
10113 
10114     operator Vk${structureType} &() VULKAN_HPP_NOEXCEPT
10115     {
10116       return *reinterpret_cast<Vk${structureType}*>( this );
10117     }
10118 ${reflect}
10119 ${compareOperators}
10120     public:
10121 ${members}
10122   };
10123 )";
10124 
10125   std::string allowDuplicate, typeValue;
10126   if ( !sTypeValue.empty() )
10127   {
10128     allowDuplicate = std::string( "    static const bool allowDuplicate = " ) + ( structure.second.allowDuplicate ? "true;" : "false;" );
10129     typeValue      = "    static VULKAN_HPP_CONST_OR_CONSTEXPR StructureType structureType = StructureType::" + sTypeValue + ";\n";
10130   }
10131   str += replaceWithMap( structureTemplate,
10132                          { { "allowDuplicate", allowDuplicate },
10133                            { "constructorsAndSetters", constructorsAndSetters },
10134                            { "compareOperators", compareOperators },
10135                            { "members", members },
10136                            { "reflect", reflect },
10137                            { "structureType", structureType },
10138                            { "typeValue", typeValue } } );
10139 
10140   if ( !sTypeValue.empty() )
10141   {
10142     std::string cppTypeTemplate = R"(
10143   template <>
10144   struct CppType<StructureType, StructureType::${sTypeValue}>
10145   {
10146     using Type = ${structureType};
10147   };
10148 )";
10149     str += replaceWithMap( cppTypeTemplate, { { "sTypeValue", sTypeValue }, { "structureType", structureType } } );
10150   }
10151 
10152   auto aliasIt = m_structureAliasesInverse.find( structure.first );
10153   if ( aliasIt != m_structureAliasesInverse.end() )
10154   {
10155     for ( std::string const & alias : aliasIt->second )
10156     {
10157       str += "  using " + stripPrefix( alias, "Vk" ) + " = " + structureType + ";\n";
10158     }
10159   }
10160 
10161   str += leave;
10162   return str;
10163 }
10164 
generateStructExtendsStructs() const10165 std::string VulkanHppGenerator::generateStructExtendsStructs() const
10166 {
10167   const std::string structExtendsTemplate = R"(
10168   //=======================
10169   //=== STRUCTS EXTENDS ===
10170   //=======================
10171 
10172 ${structExtends})";
10173 
10174   std::string           structExtends;
10175   std::set<std::string> listedStructs;
10176   for ( auto const & feature : m_features )
10177   {
10178     structExtends += generateStructExtendsStructs( feature.second.requireData, listedStructs, feature.first );
10179   }
10180   for ( auto const & extIt : m_extensionsByNumber )
10181   {
10182     structExtends += generateStructExtendsStructs( extIt.second->second.requireData, listedStructs, extIt.second->first );
10183   }
10184 
10185   return replaceWithMap( structExtendsTemplate, { { "structExtends", structExtends } } );
10186 }
10187 
generateStructExtendsStructs(std::vector<RequireData> const & requireData,std::set<std::string> & listedStructs,std::string const & title) const10188 std::string VulkanHppGenerator::generateStructExtendsStructs( std::vector<RequireData> const & requireData,
10189                                                               std::set<std::string> &          listedStructs,
10190                                                               std::string const &              title ) const
10191 {
10192   std::string str;
10193   for ( auto const & require : requireData )
10194   {
10195     for ( auto const & type : require.types )
10196     {
10197       auto structIt = m_structures.find( type );
10198       if ( structIt != m_structures.end() )
10199       {
10200         assert( listedStructs.find( type ) == listedStructs.end() );
10201         listedStructs.insert( type );
10202 
10203         auto [enter, leave] = generateProtection( getProtectFromTitle( title ) );
10204 
10205         // append all allowed structure chains
10206         for ( auto extendName : structIt->second.structExtends )
10207         {
10208           std::map<std::string, StructureData>::const_iterator itExtend = m_structures.find( extendName );
10209           if ( itExtend == m_structures.end() )
10210           {
10211             // look if the extendName acutally is an alias of some other structure
10212             auto aliasIt = m_structureAliases.find( extendName );
10213             if ( aliasIt != m_structureAliases.end() )
10214             {
10215               itExtend = m_structures.find( aliasIt->second.alias );
10216               assert( itExtend != m_structures.end() );
10217             }
10218           }
10219 
10220           auto [subEnter, subLeave] = generateProtection(
10221             m_structureAliasesInverse.find( itExtend->first ) == m_structureAliasesInverse.end() ? getProtectFromType( itExtend->first ) : "" );
10222 
10223           if ( enter != subEnter )
10224           {
10225             str += subEnter;
10226           }
10227 
10228           str += "  template <> struct StructExtends<" + stripPrefix( structIt->first, "Vk" ) + ", " + stripPrefix( extendName, "Vk" ) +
10229                  ">{ enum { value = true }; };\n";
10230 
10231           if ( leave != subLeave )
10232           {
10233             str += subLeave;
10234           }
10235         }
10236       }
10237     }
10238   }
10239   return addTitleAndProtection( title, str );
10240 }
10241 
generateStructForwardDeclarations() const10242 std::string VulkanHppGenerator::generateStructForwardDeclarations() const
10243 {
10244   const std::string fowardDeclarationsTemplate = R"(
10245   //===================================
10246   //=== STRUCT forward declarations ===
10247   //===================================
10248 
10249 ${forwardDeclarations}
10250 )";
10251 
10252   std::string forwardDeclarations;
10253   for ( auto const & feature : m_features )
10254   {
10255     forwardDeclarations += generateStructForwardDeclarations( feature.second.requireData, feature.first );
10256   }
10257   for ( auto const & extIt : m_extensionsByNumber )
10258   {
10259     forwardDeclarations += generateStructForwardDeclarations( extIt.second->second.requireData, extIt.second->first );
10260   }
10261 
10262   return replaceWithMap( fowardDeclarationsTemplate, { { "forwardDeclarations", forwardDeclarations } } );
10263 }
10264 
generateStructForwardDeclarations(std::vector<RequireData> const & requireData,std::string const & title) const10265 std::string VulkanHppGenerator::generateStructForwardDeclarations( std::vector<RequireData> const & requireData, std::string const & title ) const
10266 {
10267   std::string str;
10268   for ( auto const & require : requireData )
10269   {
10270     for ( auto const & type : require.types )
10271     {
10272       auto structIt = m_structures.find( type );
10273       if ( structIt != m_structures.end() )
10274       {
10275         std::string structureType = stripPrefix( structIt->first, "Vk" );
10276         str += ( structIt->second.isUnion ? "  union " : "  struct " ) + structureType + ";\n";
10277         auto inverseIt = m_structureAliasesInverse.find( type );
10278         if ( inverseIt != m_structureAliasesInverse.end() )
10279         {
10280           for ( auto alias : inverseIt->second )
10281           {
10282             str += "  using " + stripPrefix( alias, "Vk" ) + " = " + structureType + ";\n";
10283           }
10284         }
10285       }
10286     }
10287   }
10288   return addTitleAndProtection( title, str );
10289 }
10290 
10291 std::tuple<std::string, std::string, std::string, std::string>
generateStructMembers(std::pair<std::string,StructureData> const & structData) const10292   VulkanHppGenerator::generateStructMembers( std::pair<std::string, StructureData> const & structData ) const
10293 {
10294   std::string members, memberNames, memberTypes, sTypeValue;
10295   for ( auto const & member : structData.second.members )
10296   {
10297     members += "    ";
10298     std::string type;
10299     if ( !member.bitCount.empty() && member.type.type.starts_with( "Vk" ) )
10300     {
10301       assert( member.type.prefix.empty() && member.type.postfix.empty() );  // never encounterd a different case
10302       type = member.type.type;
10303     }
10304     else if ( member.arraySizes.empty() )
10305     {
10306       type = member.type.compose( "VULKAN_HPP_NAMESPACE" );
10307     }
10308     else
10309     {
10310       assert( member.type.prefix.empty() && member.type.postfix.empty() );
10311       type = generateStandardArrayWrapper( member.type.compose( "VULKAN_HPP_NAMESPACE" ), member.arraySizes );
10312     }
10313     members += type + " " + member.name;
10314     if ( !member.value.empty() )
10315     {
10316       // special handling for members with legal value: use it as the default
10317       members += " = ";
10318       if ( member.type.type == "uint32_t" )
10319       {
10320         members += member.value;
10321       }
10322       else
10323       {
10324         auto enumIt = m_enums.find( member.type.type );
10325         assert( enumIt != m_enums.end() );
10326         std::string enumValue = member.value;
10327         auto        valueIt   = std::find_if(
10328           enumIt->second.values.begin(), enumIt->second.values.end(), [&enumValue]( EnumValueData const & evd ) { return enumValue == evd.name; } );
10329         assert( valueIt != enumIt->second.values.end() );
10330         std::string valueName = generateEnumValueName( enumIt->first, valueIt->name, enumIt->second.isBitmask, m_tags );
10331         members += stripPrefix( member.type.type, "Vk" ) + "::" + valueName;
10332         if ( member.name == "sType" )
10333         {
10334           sTypeValue = valueName;
10335         }
10336       }
10337     }
10338     else
10339     {
10340       // as we don't have any meaningful default initialization values, everything can be initialized by just '{}'
10341       // !
10342       assert( member.arraySizes.empty() || member.bitCount.empty() );
10343       if ( !member.bitCount.empty() )
10344       {
10345         members += " : " + member.bitCount;  // except for bitfield members, where no default member initializatin
10346                                              // is supported (up to C++20)
10347       }
10348       else
10349       {
10350         members += " = ";
10351         auto enumIt = m_enums.find( member.type.type );
10352         if ( member.arraySizes.empty() && ( enumIt != m_enums.end() ) && member.type.postfix.empty() )
10353         {
10354           members += generateEnumInitializer( member.type, member.arraySizes, enumIt->second.values, enumIt->second.isBitmask );
10355         }
10356         else
10357         {
10358           members += "{}";
10359         }
10360       }
10361     }
10362     members += ";\n";
10363 
10364     memberNames += member.name + ", ";
10365     memberTypes += type + " const &, ";
10366   }
10367   return std::make_tuple( members, stripPostfix( memberNames, ", " ), stripPostfix( memberTypes, ", " ), sTypeValue );
10368 }
10369 
generateStructSetter(std::string const & structureName,std::vector<MemberData> const & memberData,size_t index) const10370 std::string VulkanHppGenerator::generateStructSetter( std::string const & structureName, std::vector<MemberData> const & memberData, size_t index ) const
10371 {
10372   std::string        str;
10373   MemberData const & member = memberData[index];
10374   if ( member.type.type != "VkStructureType" )  // filter out StructureType, which is supposed to be immutable !
10375   {
10376     static const std::string templateString = R"(
10377     ${constexpr}${structureName} & set${MemberName}( ${memberType} ${reference}${memberName}_ ) VULKAN_HPP_NOEXCEPT
10378     {
10379       ${assignment};
10380       return *this;
10381     }
10382 )";
10383 
10384     std::string memberType         = member.arraySizes.empty() ? member.type.compose( "VULKAN_HPP_NAMESPACE" )
10385                                                                : generateStandardArray( member.type.compose( "VULKAN_HPP_NAMESPACE" ), member.arraySizes );
10386     bool        isReinterpretation = !member.bitCount.empty() && member.type.type.starts_with( "Vk" );
10387     std::string assignment;
10388     if ( isReinterpretation )
10389     {
10390       assignment = member.name + " = " + "*reinterpret_cast<" + member.type.type + "*>(&" + member.name + "_)";
10391     }
10392     else
10393     {
10394       assignment = member.name + " = " + member.name + "_";
10395     }
10396 
10397     str +=
10398       replaceWithMap( templateString,
10399                       { { "assignment", assignment },
10400                         { "constexpr", isReinterpretation ? "" : "VULKAN_HPP_CONSTEXPR_14 " },
10401                         { "memberName", member.name },
10402                         { "MemberName", startUpperCase( member.name ) },
10403                         { "memberType", memberType },
10404                         { "reference", ( member.type.postfix.empty() && ( m_structures.find( member.type.type ) != m_structures.end() ) ) ? "const & " : "" },
10405                         { "structureName", structureName } } );
10406 
10407     if ( hasLen( memberData, member ) )
10408     {
10409       assert( member.name.front() == 'p' );
10410       std::string arrayName = startLowerCase( stripPrefix( member.name, "p" ) );
10411 
10412       std::string lenName, lenValue;
10413       if ( member.len[0] == "codeSize / 4" )
10414       {
10415         lenName  = "codeSize";
10416         lenValue = arrayName + "_.size() * 4";
10417       }
10418       else
10419       {
10420         lenName  = member.len[0];
10421         lenValue = arrayName + "_.size()";
10422       }
10423 
10424       assert( memberType.back() == '*' );
10425       memberType = trimEnd( stripPostfix( memberType, "*" ) );
10426 
10427       std::string templateHeader;
10428       if ( ( member.type.type == "void" ) && ( memberType.find( '*' ) == std::string::npos ) )
10429       {
10430         assert( templateHeader.empty() );
10431         templateHeader = "template <typename T>\n    ";
10432 
10433         size_t pos = memberType.find( "void" );
10434         assert( pos != std::string::npos );
10435         memberType.replace( pos, strlen( "void" ), "T" );
10436 
10437         lenValue += " * sizeof(T)";
10438       }
10439 
10440       auto lenMember = findStructMemberIt( lenName, memberData );
10441       assert( lenMember != memberData.end() && lenMember->type.prefix.empty() && lenMember->type.postfix.empty() );
10442       if ( lenMember->type.type != "size_t" )
10443       {
10444         lenValue = "static_cast<" + lenMember->type.type + ">( " + lenValue + " )";
10445       }
10446 
10447       static const std::string setArrayTemplate = R"(
10448 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
10449     ${templateHeader}${structureName} & set${ArrayName}( VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<${memberType}> const & ${arrayName}_ ) VULKAN_HPP_NOEXCEPT
10450     {
10451       ${lenName} = ${lenValue};
10452       ${memberName} = ${arrayName}_.data();
10453       return *this;
10454     }
10455 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
10456 )";
10457 
10458       str += replaceWithMap( setArrayTemplate,
10459                              { { "arrayName", arrayName },
10460                                { "ArrayName", startUpperCase( arrayName ) },
10461                                { "lenName", lenName },
10462                                { "lenValue", lenValue },
10463                                { "memberName", member.name },
10464                                { "memberType", memberType },
10465                                { "structureName", structureName },
10466                                { "templateHeader", templateHeader } } );
10467     }
10468   }
10469   return str;
10470 }
10471 
generateStructSubConstructor(std::pair<std::string,StructureData> const & structData) const10472 std::string VulkanHppGenerator::generateStructSubConstructor( std::pair<std::string, StructureData> const & structData ) const
10473 {
10474   if ( !structData.second.subStruct.empty() )
10475   {
10476     auto const & subStruct = m_structures.find( structData.second.subStruct );
10477     assert( subStruct != m_structures.end() );
10478 
10479     std::string subStructArgumentName = startLowerCase( stripPrefix( subStruct->first, "Vk" ) );
10480 
10481     std::string subCopies;
10482     bool        firstArgument = true;
10483     for ( size_t i = 0; i < subStruct->second.members.size(); i++ )
10484     {
10485       assert( structData.second.members[i].arraySizes.empty() );
10486       static const std::string subCopiesTemplate =
10487         R"(      ${separator} ${structMemberName}( ${subStructArgumentName}.${subStructMemberName} )
10488 )";
10489       subCopies += replaceWithMap( subCopiesTemplate,
10490                                    { { "separator", firstArgument ? ":" : "," },
10491                                      { "structMemberName", structData.second.members[i].name },
10492                                      { "subStructMemberName", subStruct->second.members[i].name },
10493                                      { "subStructArgumentName", subStructArgumentName } } );
10494       firstArgument = false;
10495     }
10496 
10497     std::string subArguments;
10498     bool        listedArgument = true;
10499     for ( size_t i = subStruct->second.members.size(); i < structData.second.members.size(); i++ )
10500     {
10501       std::string argument = generateStructConstructorArgument( listedArgument, structData.second.members[i], true );
10502       if ( !argument.empty() )
10503       {
10504         listedArgument = true;
10505         subArguments += argument;
10506       }
10507 
10508       assert( structData.second.members[i].arraySizes.empty() );
10509       static const std::string subCopiesTemplate = R"(    , ${memberName}( ${memberName}_ )
10510 )";
10511       subCopies += replaceWithMap( subCopiesTemplate, { { "memberName", structData.second.members[i].name } } );
10512     }
10513 
10514     static const std::string subStructConstructorTemplate = R"(
10515     explicit ${structName}( ${subStructName} const & ${subStructArgumentName}${subArguments} )
10516 ${subCopies}    {}
10517 )";
10518     return replaceWithMap( subStructConstructorTemplate,
10519                            { { "structName", stripPrefix( structData.first, "Vk" ) },
10520                              { "subArguments", subArguments },
10521                              { "subCopies", subCopies },
10522                              { "subStructArgumentName", subStructArgumentName },
10523                              { "subStructName", stripPrefix( subStruct->first, "Vk" ) } } );
10524   }
10525   return "";
10526 }
10527 
generateSuccessCheck(std::vector<std::string> const & successCodes) const10528 std::string VulkanHppGenerator::generateSuccessCheck( std::vector<std::string> const & successCodes ) const
10529 {
10530   assert( !successCodes.empty() );
10531   std::string successCheck = "result == " + generateSuccessCode( successCodes[0], m_tags );
10532   if ( 1 < successCodes.size() )
10533   {
10534     successCheck = "( " + successCheck + " )";
10535     for ( size_t i = 1; i < successCodes.size(); ++i )
10536     {
10537       successCheck += "|| ( result == " + generateSuccessCode( successCodes[i], m_tags ) + " )";
10538     }
10539   }
10540   return successCheck;
10541 }
10542 
generateSuccessCodeList(std::vector<std::string> const & successCodes,bool enumerating) const10543 std::string VulkanHppGenerator::generateSuccessCodeList( std::vector<std::string> const & successCodes, bool enumerating ) const
10544 {
10545   std::string successCodeList;
10546   if ( ( 1 < successCodes.size() ) && !enumerating )
10547   {
10548     successCodeList = ", { " + generateSuccessCode( successCodes[0], m_tags );
10549     for ( size_t i = 1; i < successCodes.size(); ++i )
10550     {
10551       successCodeList += ", " + generateSuccessCode( successCodes[i], m_tags );
10552     }
10553     successCodeList += " }";
10554   }
10555   return successCodeList;
10556 }
10557 
generateThrowResultException() const10558 std::string VulkanHppGenerator::generateThrowResultException() const
10559 {
10560   auto enumIt = m_enums.find( "VkResult" );
10561 
10562   std::string cases;
10563   for ( auto const & value : enumIt->second.values )
10564   {
10565     if ( value.name.starts_with( "VK_ERROR" ) )
10566     {
10567       auto [enter, leave]   = generateProtection( getProtect( value ) );
10568       std::string valueName = generateEnumValueName( enumIt->first, value.name, false, m_tags );
10569       cases += enter + "      case Result::" + valueName + ": throw " + stripPrefix( valueName, "eError" ) + "Error( message );\n" + leave;
10570     }
10571   }
10572   cases.pop_back();  // remove last newline
10573 
10574   const std::string throwTemplate = R"(
10575   namespace
10576   {
10577     [[noreturn]] void throwResultException( Result result, char const * message )
10578     {
10579       switch ( result )
10580       {
10581 ${cases}
10582         default: throw SystemError( make_error_code( result ) );
10583       }
10584     }
10585   })";
10586   return replaceWithMap( throwTemplate, { { "cases", cases } } );
10587 }
10588 
generateTypenameCheck(std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,bool definition,std::vector<std::string> const & dataTypes,CommandFlavourFlags flavourFlags) const10589 std::string VulkanHppGenerator::generateTypenameCheck( std::vector<size_t> const &               returnParams,
10590                                                        std::map<size_t, VectorParamData> const & vectorParams,
10591                                                        bool                                      definition,
10592                                                        std::vector<std::string> const &          dataTypes,
10593                                                        CommandFlavourFlags                       flavourFlags ) const
10594 {
10595   std::string typenameCheck, enableIf;
10596   if ( !( flavourFlags & CommandFlavourFlagBits::singular ) && ( flavourFlags & CommandFlavourFlagBits::withAllocator ) )
10597   {
10598     for ( size_t i = 0; i < returnParams.size(); ++i )
10599     {
10600       if ( vectorParams.find( returnParams[i] ) != vectorParams.end() )
10601       {
10602         std::string elementType = ( flavourFlags & CommandFlavourFlagBits::chained ) ? "StructureChain" : stripPrefix( dataTypes[i], "VULKAN_HPP_NAMESPACE::" );
10603         std::string extendedElementType = elementType;
10604         if ( flavourFlags & CommandFlavourFlagBits::unique )
10605         {
10606           extendedElementType = "UniqueHandle<" + elementType + ", Dispatch>";
10607         }
10608         std::string index = std::to_string( i );
10609         if ( definition )
10610         {
10611           typenameCheck += ", typename B" + index;
10612         }
10613         else
10614         {
10615           typenameCheck += ", typename B" + index + " = " + startUpperCase( elementType ) + "Allocator";
10616         }
10617         enableIf += enableIf.empty() ? ", typename std::enable_if<" : " && ";
10618         enableIf += "std::is_same<typename B" + index + "::value_type, " + extendedElementType + ">::value";
10619       }
10620     }
10621     assert( !typenameCheck.empty() );
10622     if ( !typenameCheck.empty() )
10623     {
10624       typenameCheck += enableIf + ", int>::type";
10625       if ( !definition )
10626       {
10627         typenameCheck += " = 0";
10628       }
10629     }
10630   }
10631   return typenameCheck;
10632 }
10633 
generateUnion(std::pair<std::string,StructureData> const & structure) const10634 std::string VulkanHppGenerator::generateUnion( std::pair<std::string, StructureData> const & structure ) const
10635 {
10636   auto [enter, leave] =
10637     generateProtection( m_structureAliasesInverse.find( structure.first ) == m_structureAliasesInverse.end() ? getProtectFromType( structure.first ) : "" );
10638   std::string unionName = stripPrefix( structure.first, "Vk" );
10639 
10640   bool               firstMember = true;
10641   std::set<TypeInfo> listedTypes;  // create just one constructor per different type !
10642   std::string        constructors;
10643   for ( auto memberIt = structure.second.members.begin(); memberIt != structure.second.members.end(); ++memberIt )
10644   {
10645     if ( listedTypes.insert( memberIt->type ).second )
10646     {
10647       // VkBool32 is aliased to uint32_t. Don't create a VkBool32 constructor if the union also contains a
10648       // uint32_t constructor.
10649       if ( memberIt->type.type == "VkBool32" )
10650       {
10651         if ( findStructMemberItByType( "uint32_t", structure.second.members ) != structure.second.members.end() )
10652         {
10653           continue;
10654         }
10655       }
10656 
10657       bool multipleType =
10658         ( std::find_if( std::next( memberIt ),
10659                         structure.second.members.end(),
10660                         [memberIt]( MemberData const & member ) { return member.type == memberIt->type; } ) != structure.second.members.end() );
10661       std::string memberType = ( memberIt->arraySizes.empty() )
10662                                ? memberIt->type.compose( "VULKAN_HPP_NAMESPACE" )
10663                                : ( "const " + generateStandardArray( memberIt->type.compose( "VULKAN_HPP_NAMESPACE" ), memberIt->arraySizes ) + "&" );
10664 
10665       // In a majority of cases this can be constexpr in C++11 as well, however, determining when exactly
10666       // that is the case is a lot more involved and probably not worth it.
10667       static const std::string constructorTemplate = R"(
10668     VULKAN_HPP_CONSTEXPR_14 ${unionName}( ${memberType} ${argumentName}_${defaultAssignment} )
10669       : ${memberName}( ${argumentName}_ )
10670     {})";
10671 
10672       constructors += ( firstMember ? "" : "\n" ) + replaceWithMap( constructorTemplate,
10673                                                                     { { "argumentName", multipleType ? generateName( memberIt->type ) : memberIt->name },
10674                                                                       { "defaultAssignment", firstMember ? " = {}" : "" },
10675                                                                       { "memberName", memberIt->name },
10676                                                                       { "memberType", memberType },
10677                                                                       { "unionName", stripPrefix( structure.first, "Vk" ) } } );
10678       firstMember = false;
10679 
10680       if ( !memberIt->arraySizes.empty() )
10681       {
10682         assert( !multipleType );
10683         assert( memberIt->arraySizes.size() == 1 );
10684         int size = std::stoi( memberIt->arraySizes[0] );
10685         assert( std::to_string( size ) == memberIt->arraySizes[0] );
10686         std::string arguments, callArguments;
10687         bool        firstArgument = true;
10688         for ( int i = 0; i < size; i++ )
10689         {
10690           if ( !firstArgument )
10691           {
10692             arguments += ", ";
10693             callArguments += ", ";
10694           }
10695           std::string argumentIndex = std::to_string( i );
10696           arguments += memberIt->type.type + " " + memberIt->name + "_" + argumentIndex;
10697           callArguments += memberIt->name + "_" + argumentIndex;
10698           firstArgument = false;
10699         }
10700 
10701         static const std::string constructorBySequenceTemplate = R"(
10702     VULKAN_HPP_CONSTEXPR ${unionName}( ${arguments} )
10703       : ${memberName}{ { { ${callArguments} } } }
10704     {})";
10705 
10706         constructors += "\n" + replaceWithMap( constructorBySequenceTemplate,
10707                                                { { "arguments", arguments },
10708                                                  { "callArguments", callArguments },
10709                                                  { "memberName", memberIt->name },
10710                                                  { "unionName", stripPrefix( structure.first, "Vk" ) } } );
10711       }
10712     }
10713   }
10714 
10715   // one setter per union element
10716   std::string setters;
10717   for ( size_t i = 0; i < structure.second.members.size(); i++ )
10718   {
10719     setters += generateStructSetter( stripPrefix( structure.first, "Vk" ), structure.second.members, i );
10720   }
10721   // filter out leading and trailing newline
10722   setters = setters.substr( 1, setters.length() - 2 );
10723 
10724   // the union member variables
10725   std::string members;
10726   // if there's at least one Vk... type in this union, check for unrestricted unions support
10727   bool needsUnrestrictedUnions =
10728     ( std::find_if( structure.second.members.begin(),
10729                     structure.second.members.end(),
10730                     []( MemberData const & member ) { return member.type.type.starts_with( "Vk" ); } ) != structure.second.members.end() );
10731   if ( needsUnrestrictedUnions )
10732   {
10733     members += "#ifdef VULKAN_HPP_HAS_UNRESTRICTED_UNIONS\n";
10734   }
10735   for ( auto const & member : structure.second.members )
10736   {
10737     static const std::string memberTemplate = R"(    ${memberType} ${memberName};
10738 )";
10739     members +=
10740       replaceWithMap( memberTemplate,
10741                       { { "memberName", member.name },
10742                         { "memberType",
10743                           member.arraySizes.empty() ? member.type.compose( "VULKAN_HPP_NAMESPACE" )
10744                                                     : generateStandardArrayWrapper( member.type.compose( "VULKAN_HPP_NAMESPACE" ), member.arraySizes ) } } );
10745   }
10746   if ( needsUnrestrictedUnions )
10747   {
10748     members += "#else\n";
10749     for ( auto const & member : structure.second.members )
10750     {
10751       static const std::string memberTemplate = R"(    ${memberType} ${memberName}${arraySizes};
10752 )";
10753       members += replaceWithMap(
10754         memberTemplate,
10755         { { "arraySizes", generateCArraySizes( member.arraySizes ) }, { "memberName", member.name }, { "memberType", member.type.compose( "" ) } } );
10756     }
10757     members += "#endif  /*VULKAN_HPP_HAS_UNRESTRICTED_UNIONS*/\n";
10758   }
10759 
10760   static const std::string unionTemplate = R"(
10761 ${enter}  union ${unionName}
10762   {
10763     using NativeType = Vk${unionName};
10764 #if !defined( VULKAN_HPP_NO_UNION_CONSTRUCTORS )
10765 ${constructors}
10766 #endif /*VULKAN_HPP_NO_UNION_CONSTRUCTORS*/
10767 
10768 #if !defined( VULKAN_HPP_NO_UNION_SETTERS )
10769 ${setters}
10770 #endif /*VULKAN_HPP_NO_UNION_SETTERS*/
10771 
10772     operator Vk${unionName} const &() const
10773     {
10774       return *reinterpret_cast<const Vk${unionName}*>( this );
10775     }
10776 
10777     operator Vk${unionName} &()
10778     {
10779       return *reinterpret_cast<Vk${unionName}*>( this );
10780     }
10781 
10782 ${members}
10783   };
10784 ${leave})";
10785 
10786   return replaceWithMap(
10787     unionTemplate,
10788     { { "constructors", constructors }, { "enter", enter }, { "leave", leave }, { "members", members }, { "setters", setters }, { "unionName", unionName } } );
10789 }
10790 
generateUniqueTypes(std::string const & parentType,std::set<std::string> const & childrenTypes) const10791 std::string VulkanHppGenerator::generateUniqueTypes( std::string const & parentType, std::set<std::string> const & childrenTypes ) const
10792 {
10793   std::string childrenTraits;
10794   for ( auto const & childType : childrenTypes )
10795   {
10796     auto handleIt = m_handles.find( childType );
10797     assert( handleIt != m_handles.end() );
10798 
10799     std::string type = stripPrefix( childType, "Vk" );
10800 
10801     auto [enter, leave] = generateProtection( handleIt->second.alias.empty() ? getProtectFromType( handleIt->first ) : "" );
10802 
10803     std::string aliasHandle;
10804     if ( !handleIt->second.alias.empty() )
10805     {
10806       static const std::string aliasHandleTemplate =
10807         R"(  using Unique${aliasType} = UniqueHandle<${type}, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>;
10808 )";
10809 
10810       aliasHandle += replaceWithMap( aliasHandleTemplate, { { "aliasType", stripPrefix( handleIt->second.alias, "Vk" ) }, { "type", type } } );
10811     }
10812 
10813     static const std::string traitsTemplate = R"(${enter}  template <typename Dispatch>
10814   class UniqueHandleTraits<${type}, Dispatch>
10815   {
10816   public:
10817     using deleter = ${deleterType}${deleterAction}<${deleterParent}${deleterPool}, Dispatch>;
10818   };
10819   using Unique${type} = UniqueHandle<${type}, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>;
10820 ${aliasHandle}${leave})";
10821 
10822     childrenTraits += replaceWithMap( traitsTemplate,
10823                                       { { "aliasHandle", aliasHandle },
10824                                         { "deleterAction", ( handleIt->second.deleteCommand.substr( 2, 4 ) == "Free" ) ? "Free" : "Destroy" },
10825                                         { "deleterParent", parentType.empty() ? "NoParent" : stripPrefix( parentType, "Vk" ) },
10826                                         { "deleterPool", handleIt->second.deletePool.empty() ? "" : ", " + stripPrefix( handleIt->second.deletePool, "Vk" ) },
10827                                         { "deleterType", handleIt->second.deletePool.empty() ? "Object" : "Pool" },
10828                                         { "enter", enter },
10829                                         { "leave", leave },
10830                                         { "type", type } } );
10831   }
10832 
10833   static const std::string uniqueTypeTemplate = R"(
10834 #ifndef VULKAN_HPP_NO_SMART_HANDLE
10835 ${parentClass}${childrenTraits}#endif /*VULKAN_HPP_NO_SMART_HANDLE*/
10836 )";
10837 
10838   return replaceWithMap(
10839     uniqueTypeTemplate,
10840     { { "childrenTraits", childrenTraits }, { "parentClass", parentType.empty() ? "" : ( "  class " + stripPrefix( parentType, "Vk" ) + ";\n" ) } } );
10841 }
10842 
generateVectorSizeCheck(std::string const & name,CommandData const & commandData,size_t initialSkipCount,std::map<size_t,std::vector<size_t>> const & countToVectorMap,std::set<size_t> const & skippedParams,bool onlyThrows) const10843 std::string VulkanHppGenerator::generateVectorSizeCheck( std::string const &                           name,
10844                                                          CommandData const &                           commandData,
10845                                                          size_t                                        initialSkipCount,
10846                                                          std::map<size_t, std::vector<size_t>> const & countToVectorMap,
10847                                                          std::set<size_t> const &                      skippedParams,
10848                                                          bool                                          onlyThrows ) const
10849 {
10850   std::string const assertTemplate = "    VULKAN_HPP_ASSERT( ${zeroSizeCheck}${firstVectorName}.size() == ${secondVectorName}.size() );";
10851   std::string const assertTemplateVoid =
10852     "    VULKAN_HPP_ASSERT( ${zeroSizeCheck}${firstVectorName}.size() * sizeof( ${firstDataType} ) == ${secondVectorName}.size() * sizeof( ${secondDataType} ) );";
10853   std::string const assertTemplateByLen = "    VULKAN_HPP_ASSERT( ${vectorName}.size() == ${sizeValue} );";
10854   std::string const throwTemplate =
10855     R"#(    if ( ${zeroSizeCheck}${firstVectorName}.size() != ${secondVectorName}.size() )
10856   {
10857     throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() != ${secondVectorName}.size()" );
10858   })#";
10859   std::string const throwTemplateVoid =
10860     R"#(    if ( ${zeroSizeCheck}${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} ) )
10861   {
10862     throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} )" );
10863   })#";
10864   std::string const throwTemplateByLen = R"#(    if ( ${vectorName}.size() != ${sizeValue} )
10865     {
10866       throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${vectorName}.size() != ${sizeValue}" );
10867     })#";
10868 
10869   std::string className   = stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" );
10870   std::string commandName = generateCommandName( name, commandData.params, initialSkipCount, m_tags );
10871 
10872   std::string assertions, throws;
10873   for ( auto const & cvm : countToVectorMap )
10874   {
10875     size_t      defaultStartIndex = determineDefaultStartIndex( commandData.params, skippedParams );
10876     std::string firstVectorName   = startLowerCase( stripPrefix( commandData.params[cvm.second[0]].name, "p" ) );
10877 
10878     if ( cvm.second.size() == 1 )
10879     {
10880       assert( isLenByStructMember( commandData.params[cvm.second[0]].len, commandData.params[cvm.first] ) );
10881 
10882       std::vector<std::string> lenParts = tokenize( commandData.params[cvm.second[0]].len, "->" );
10883       assert( lenParts.size() == 2 );
10884       std::string sizeValue = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
10885       assertions += replaceWithMap( assertTemplateByLen, { { "sizeValue", sizeValue }, { "vectorName", firstVectorName } } );
10886       throws += replaceWithMap( throwTemplateByLen,
10887                                 { { "className", className }, { "commandName", commandName }, { "sizeValue", sizeValue }, { "vectorName", firstVectorName } } );
10888     }
10889     else
10890     {
10891       for ( size_t i = 1; i < cvm.second.size(); i++ )
10892       {
10893         std::string secondVectorName  = startLowerCase( stripPrefix( commandData.params[cvm.second[i]].name, "p" ) );
10894         bool        withZeroSizeCheck = commandData.params[cvm.second[i]].optional && ( defaultStartIndex <= cvm.second[i] );
10895         if ( commandData.params[cvm.second[0]].type.type == "void" )
10896         {
10897           assert( commandData.params[cvm.second[i]].type.type == "void" );
10898           std::string firstDataType  = stripPrefix( commandData.params[cvm.second[0]].name, "p" ) + "Type";
10899           std::string secondDataType = stripPrefix( commandData.params[cvm.second[i]].name, "p" ) + "Type";
10900           assertions += replaceWithMap( assertTemplateVoid,
10901                                         { { "firstDataType", firstDataType },
10902                                           { "firstVectorName", firstVectorName },
10903                                           { "secondDataType", secondDataType },
10904                                           { "secondVectorName", secondVectorName },
10905                                           { "zeroSizeCheck", withZeroSizeCheck ? ( secondVectorName + ".empty() || " ) : "" } } );
10906           throws += replaceWithMap( throwTemplateVoid,
10907                                     { { "firstDataType", firstDataType },
10908                                       { "firstVectorName", firstVectorName },
10909                                       { "className", className },
10910                                       { "commandName", commandName },
10911                                       { "secondDataType", secondDataType },
10912                                       { "secondVectorName", secondVectorName },
10913                                       { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
10914         }
10915         else
10916         {
10917           assertions += replaceWithMap( assertTemplate,
10918                                         { { "firstVectorName", firstVectorName },
10919                                           { "secondVectorName", secondVectorName },
10920                                           { "zeroSizeCheck", withZeroSizeCheck ? ( secondVectorName + ".empty() || " ) : "" } } );
10921           throws += replaceWithMap( throwTemplate,
10922                                     { { "firstVectorName", firstVectorName },
10923                                       { "className", className },
10924                                       { "commandName", commandName },
10925                                       { "secondVectorName", secondVectorName },
10926                                       { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
10927         }
10928         if ( i + 1 < cvm.second.size() )
10929         {
10930           assertions += "\n";
10931           throws += "\n";
10932         }
10933       }
10934     }
10935   }
10936 
10937   std::string const sizeCheckTemplate =
10938     R"(#ifdef VULKAN_HPP_NO_EXCEPTIONS
10939 ${assertions}
10940 #else
10941 ${throws}
10942 #endif  /*VULKAN_HPP_NO_EXCEPTIONS*/)";
10943 
10944   return onlyThrows ? throws : replaceWithMap( sizeCheckTemplate, { { "assertions", assertions }, { "throws", throws } } );
10945 }
10946 
getParentTypeAndName(std::pair<std::string,HandleData> const & handle) const10947 std::pair<std::string, std::string> VulkanHppGenerator::getParentTypeAndName( std::pair<std::string, HandleData> const & handle ) const
10948 {
10949   std::string parentType, parentName;
10950   if ( handle.first == "VkInstance" )
10951   {
10952     parentType = "Context";
10953     parentName = "context";
10954   }
10955   else
10956   {
10957     bool skip = skipLeadingGrandParent( handle );
10958     assert( !handle.second.constructorIts.empty() && ( ( skip ? 1u : 0u ) < handle.second.constructorIts.front()->second.params.size() ) );
10959     auto const & param = handle.second.constructorIts.front()->second.params[skip ? 1 : 0];
10960     assert( isHandleType( param.type.type ) && param.type.isValue() );
10961     parentType = stripPrefix( param.type.type, "Vk" );
10962     parentName = param.name;
10963   }
10964   return std::make_pair( parentType, parentName );
10965 }
10966 
getPlatform(std::string const & title) const10967 std::string VulkanHppGenerator::getPlatform( std::string const & title ) const
10968 {
10969   if ( m_features.find( title ) == m_features.end() )
10970   {
10971     auto extensionIt = m_extensions.find( title );
10972     assert( extensionIt != m_extensions.end() );
10973     return extensionIt->second.platform;
10974   }
10975   return "";
10976 }
10977 
getPoolTypeAndName(std::string const & type) const10978 std::pair<std::string, std::string> VulkanHppGenerator::getPoolTypeAndName( std::string const & type ) const
10979 {
10980   auto structIt = m_structures.find( type );
10981   assert( structIt != m_structures.end() );
10982   auto memberIt = std::find_if(
10983     structIt->second.members.begin(), structIt->second.members.end(), []( MemberData const & md ) { return md.name.find( "Pool" ) != std::string::npos; } );
10984   assert( memberIt != structIt->second.members.end() );
10985   assert( std::find_if( std::next( memberIt ),
10986                         structIt->second.members.end(),
10987                         []( MemberData const & md ) { return md.name.find( "Pool" ) != std::string::npos; } ) == structIt->second.members.end() );
10988   return std::make_pair( memberIt->type.type, memberIt->name );
10989 }
10990 
getProtect(EnumValueData const & evd) const10991 std::string VulkanHppGenerator::getProtect( EnumValueData const & evd ) const
10992 {
10993   assert( evd.protect.empty() || ( evd.protect == getProtectFromTitle( evd.extension ) ) );
10994   return evd.protect.empty() ? getProtectFromTitle( evd.extension ) : evd.protect;
10995 }
10996 
getProtectFromPlatform(std::string const & platform) const10997 std::string VulkanHppGenerator::getProtectFromPlatform( std::string const & platform ) const
10998 {
10999   auto platformIt = m_platforms.find( platform );
11000   return ( platformIt != m_platforms.end() ) ? platformIt->second.protect : "";
11001 }
11002 
getProtectFromTitle(std::string const & title) const11003 std::string VulkanHppGenerator::getProtectFromTitle( std::string const & title ) const
11004 {
11005   if ( m_features.find( title ) == m_features.end() )
11006   {
11007     auto extensionIt = m_extensions.find( title );
11008     return ( extensionIt != m_extensions.end() ) ? getProtectFromPlatform( extensionIt->second.platform ) : "";
11009   }
11010   return "";
11011 }
11012 
getProtectFromType(std::string const & type) const11013 std::string VulkanHppGenerator::getProtectFromType( std::string const & type ) const
11014 {
11015   auto typeIt = m_types.find( type );
11016   assert( typeIt != m_types.end() );
11017   return getProtectFromTitle( typeIt->second.referencedIn );
11018 }
11019 
getVectorSize(std::vector<ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams,size_t returnParam,std::string const & returnParamType,std::set<size_t> const & templatedParams) const11020 std::string VulkanHppGenerator::getVectorSize( std::vector<ParamData> const &            params,
11021                                                std::map<size_t, VectorParamData> const & vectorParams,
11022                                                size_t                                    returnParam,
11023                                                std::string const &                       returnParamType,
11024                                                std::set<size_t> const &                  templatedParams ) const
11025 {
11026   std::string              vectorSize;
11027   std::vector<std::string> lenParts = tokenize( params[returnParam].len, "->" );
11028   switch ( lenParts.size() )
11029   {
11030     case 1:
11031       {
11032         std::string const & len = lenParts[0];
11033         size_t              lenIdx =
11034           std::distance( params.begin(), std::find_if( params.begin(), params.end(), [&len]( ParamData const & pd ) { return pd.name == len; } ) );
11035         assert( lenIdx < params.size() );
11036         // look for the len, not being the len of the return param, but of an other vector param
11037         auto lenVectorParamIt =
11038           std::find_if( vectorParams.begin(),
11039                         vectorParams.end(),
11040                         [&lenIdx, &returnParam]( auto const & vpi ) { return ( vpi.first != returnParam ) && ( vpi.second.lenParam == lenIdx ); } );
11041         if ( lenVectorParamIt == vectorParams.end() )
11042         {
11043           vectorSize = lenParts[0];
11044           if ( templatedParams.find( returnParam ) != templatedParams.end() )
11045           {
11046             vectorSize += " / sizeof( " + returnParamType + " )";
11047           }
11048         }
11049         else
11050         {
11051           assert( templatedParams.find( returnParam ) == templatedParams.end() );
11052           vectorSize = startLowerCase( stripPrefix( params[lenVectorParamIt->first].name, "p" ) ) + ".size()";
11053         }
11054       }
11055       break;
11056     case 2:
11057       assert( vectorParams.find( returnParam ) != vectorParams.end() );
11058       vectorSize = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
11059       break;
11060     default: assert( false ); break;
11061   }
11062   assert( !vectorSize.empty() );
11063   return vectorSize;
11064 }
11065 
hasLen(std::vector<MemberData> const & members,MemberData const & md) const11066 bool VulkanHppGenerator::hasLen( std::vector<MemberData> const & members, MemberData const & md ) const
11067 {
11068   if ( !md.len.empty() && !( md.len[0] == "null-terminated" ) && ( ( altLens.find( md.len[0] ) == altLens.end() ) || ( md.len[0] == "codeSize / 4" ) ) )
11069   {
11070     auto lenIt = findStructMemberIt( md.len.front(), members );
11071     return ( lenIt == members.end() ) || lenIt->type.isValue();
11072   }
11073   return false;
11074 }
11075 
hasParentHandle(std::string const & handle,std::string const & parent) const11076 bool VulkanHppGenerator::hasParentHandle( std::string const & handle, std::string const & parent ) const
11077 {
11078   std::string candidate = handle;
11079   while ( !candidate.empty() )
11080   {
11081     auto const & handleIt = m_handles.find( candidate );
11082     assert( handleIt != m_handles.end() );
11083     if ( handleIt->second.parent == parent )
11084     {
11085       return true;
11086     }
11087     else
11088     {
11089       candidate = handleIt->second.parent;
11090     }
11091   }
11092   return false;
11093 }
11094 
isDeviceCommand(CommandData const & commandData) const11095 bool VulkanHppGenerator::isDeviceCommand( CommandData const & commandData ) const
11096 {
11097   return !commandData.handle.empty() && !commandData.params.empty() && ( m_handles.find( commandData.params[0].type.type ) != m_handles.end() ) &&
11098          ( commandData.params[0].type.type != "VkInstance" ) && ( commandData.params[0].type.type != "VkPhysicalDevice" );
11099 }
11100 
isHandleType(std::string const & type) const11101 bool VulkanHppGenerator::isHandleType( std::string const & type ) const
11102 {
11103   if ( type.starts_with( "Vk" ) )
11104   {
11105     auto it = m_handles.find( type );
11106     if ( it == m_handles.end() )
11107     {
11108       it = std::find_if( m_handles.begin(), m_handles.end(), [&type]( std::pair<std::string, HandleData> const & hd ) { return hd.second.alias == type; } );
11109     }
11110     return ( it != m_handles.end() );
11111   }
11112   return false;
11113 }
11114 
isLenByStructMember(std::string const & name,std::vector<ParamData> const & params) const11115 bool VulkanHppGenerator::isLenByStructMember( std::string const & name, std::vector<ParamData> const & params ) const
11116 {
11117   // check if name specifies a member of a struct
11118   std::vector<std::string> nameParts = tokenize( name, "->" );
11119   if ( nameParts.size() == 1 )
11120   {
11121     // older versions of vk.xml used the notation parameter::member
11122     nameParts = tokenize( name, "::" );
11123   }
11124   if ( nameParts.size() == 2 )
11125   {
11126     auto paramIt = std::find_if( params.begin(), params.end(), [&n = nameParts[0]]( ParamData const & pd ) { return pd.name == n; } );
11127     if ( paramIt != params.end() )
11128     {
11129 #if !defined( NDEBUG )
11130       auto structureIt = m_structures.find( paramIt->type.type );
11131       assert( structureIt != m_structures.end() );
11132       assert( isStructMember( nameParts[1], structureIt->second.members ) );
11133 #endif
11134       return true;
11135     }
11136   }
11137   return false;
11138 }
11139 
isLenByStructMember(std::string const & name,ParamData const & param) const11140 bool VulkanHppGenerator::isLenByStructMember( std::string const & name, ParamData const & param ) const
11141 {
11142   // check if name specifies a member of a struct
11143   std::vector<std::string> nameParts = tokenize( name, "->" );
11144   if ( nameParts.size() == 1 )
11145   {
11146     // older versions of vk.xml used the notation parameter::member
11147     nameParts = tokenize( name, "::" );
11148   }
11149   if ( ( nameParts.size() == 2 ) && ( nameParts[0] == param.name ) )
11150   {
11151 #if !defined( NDEBUG )
11152     auto structureIt = m_structures.find( param.type.type );
11153     assert( structureIt != m_structures.end() );
11154     assert( isStructMember( nameParts[1], structureIt->second.members ) );
11155 #endif
11156     return true;
11157   }
11158   return false;
11159 }
11160 
isMultiSuccessCodeConstructor(std::vector<std::map<std::string,CommandData>::const_iterator> const & constructorIts) const11161 bool VulkanHppGenerator::isMultiSuccessCodeConstructor( std::vector<std::map<std::string, CommandData>::const_iterator> const & constructorIts ) const
11162 {
11163   bool ok = !constructorIts.empty();
11164   if ( ok )
11165   {
11166     auto constructorIt = constructorIts.begin();
11167     ok                 = ( 2 < ( *constructorIt )->second.successCodes.size() ) ||
11168          ( ( ( *constructorIt )->second.successCodes.size() == 2 ) && ( ( *constructorIt )->second.successCodes[1] != "VK_INCOMPLETE" ) );
11169 #if !defined( NDEBUG )
11170     for ( constructorIt = std::next( constructorIt ); constructorIt != constructorIts.end(); ++constructorIt )
11171     {
11172       assert( ok == ( 2 < ( *constructorIt )->second.successCodes.size() ) ||
11173               ( ( ( *constructorIt )->second.successCodes.size() == 2 ) && ( ( *constructorIt )->second.successCodes[1] != "VK_INCOMPLETE" ) ) );
11174     }
11175 #endif
11176   }
11177   return ok;
11178 }
11179 
isParam(std::string const & name,std::vector<ParamData> const & params) const11180 bool VulkanHppGenerator::isParam( std::string const & name, std::vector<ParamData> const & params ) const
11181 {
11182   return std::find_if( params.begin(), params.end(), [&name]( ParamData const & pd ) { return pd.name == name; } ) != params.end();
11183 }
11184 
isStructMember(std::string const & name,std::vector<MemberData> const & memberData) const11185 bool VulkanHppGenerator::isStructMember( std::string const & name, std::vector<MemberData> const & memberData ) const
11186 {
11187   return findStructMemberIt( name, memberData ) != memberData.end();
11188 }
11189 
isStructureChainAnchor(std::string const & type) const11190 bool VulkanHppGenerator::isStructureChainAnchor( std::string const & type ) const
11191 {
11192   if ( type.starts_with( "Vk" ) )
11193   {
11194     auto it = m_structures.find( type );
11195     if ( it == m_structures.end() )
11196     {
11197       auto aliasIt = m_structureAliases.find( type );
11198       if ( aliasIt != m_structureAliases.end() )
11199       {
11200         it = m_structures.find( aliasIt->second.alias );
11201       }
11202     }
11203     if ( it != m_structures.end() )
11204     {
11205       return m_extendedStructs.find( it->first ) != m_extendedStructs.end();
11206     }
11207   }
11208   return false;
11209 }
11210 
needsVectorSizeCheck(std::vector<ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,std::set<size_t> const & singularParams) const11211 std::pair<bool, std::map<size_t, std::vector<size_t>>> VulkanHppGenerator::needsVectorSizeCheck( std::vector<ParamData> const &            params,
11212                                                                                                  std::map<size_t, VectorParamData> const & vectorParams,
11213                                                                                                  std::vector<size_t> const &               returnParams,
11214                                                                                                  std::set<size_t> const & singularParams ) const
11215 {
11216   std::map<size_t, std::vector<size_t>> countToVectorMap;
11217   for ( auto const & vpi : vectorParams )
11218   {
11219     if ( ( vpi.second.lenParam != INVALID_INDEX ) && ( std::find( returnParams.begin(), returnParams.end(), vpi.first ) == returnParams.end() ) &&
11220          ( ( singularParams.find( vpi.second.lenParam ) == singularParams.end() ) ||
11221            isLenByStructMember( params[vpi.first].len, params[vpi.second.lenParam] ) ) )
11222     {
11223       countToVectorMap[vpi.second.lenParam].push_back( vpi.first );
11224     }
11225   }
11226   return std::make_pair( std::find_if( countToVectorMap.begin(),
11227                                        countToVectorMap.end(),
11228                                        [this, &params]( auto const & cvm ) {
11229                                          return ( 1 < cvm.second.size() ) || isLenByStructMember( params[cvm.second[0]].len, params[cvm.first] );
11230                                        } ) != countToVectorMap.end(),
11231                          countToVectorMap );
11232 }
11233 
readCommands(tinyxml2::XMLElement const * element)11234 void VulkanHppGenerator::readCommands( tinyxml2::XMLElement const * element )
11235 {
11236   int line = element->GetLineNum();
11237   checkAttributes( line, getAttributes( element ), {}, { { "comment", {} } } );
11238 
11239   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11240   checkElements( line, children, { { "command", false } } );
11241   for ( auto child : children )
11242   {
11243     assert( child->Value() == std::string( "command" ) );
11244     readCommandsCommand( child );
11245   }
11246 }
11247 
readCommandsCommand(tinyxml2::XMLElement const * element)11248 void VulkanHppGenerator::readCommandsCommand( tinyxml2::XMLElement const * element )
11249 {
11250   int                                line       = element->GetLineNum();
11251   std::map<std::string, std::string> attributes = getAttributes( element );
11252   if ( attributes.find( "alias" ) != attributes.end() )
11253   {
11254     // for command aliases, create a copy of the aliased command
11255     checkAttributes( line,
11256                      attributes,
11257                      {},
11258                      {
11259                        { "alias", {} },
11260                        { "name", {} },
11261                      } );
11262     checkElements( line, getChildElements( element ), {} );
11263 
11264     std::string alias, name;
11265     for ( auto const & attribute : attributes )
11266     {
11267       if ( attribute.first == "alias" )
11268       {
11269         alias = attribute.second;
11270       }
11271       else if ( attribute.first == "name" )
11272       {
11273         name = attribute.second;
11274         checkForError( name.starts_with( "vk" ), line, "name <" + name + "> should begin with <vk>" );
11275       }
11276     }
11277 
11278     auto commandIt = m_commands.find( alias );
11279     checkForError( commandIt != m_commands.end(), line, "missing command <" + alias + ">" );
11280     CommandData commandData = commandIt->second;
11281     commandData.alias       = alias;
11282     commandData.xmlLine     = line;
11283     addCommand( name, commandData );
11284   }
11285   else
11286   {
11287     checkAttributes( line,
11288                      attributes,
11289                      {},
11290                      { { "cmdbufferlevel", { "primary", "secondary" } },
11291                        { "comment", {} },
11292                        { "errorcodes", {} },
11293                        { "queues", { "compute", "decode", "encode", "graphics", "opticalflow", "sparse_binding", "transfer" } },
11294                        { "renderpass", { "both", "inside", "outside" } },
11295                        { "successcodes", {} },
11296                        { "tasks", { "action", "indirection", "state", "synchronization" } },
11297                        { "videocoding", { "both", "inside", "outside" } } } );
11298 
11299     std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11300     checkElements( line, children, { { "param", false }, { "proto", true } }, { "implicitexternsyncparams" } );
11301 
11302     CommandData commandData( line );
11303     for ( auto const & attribute : attributes )
11304     {
11305       if ( attribute.first == "errorcodes" )
11306       {
11307         commandData.errorCodes = tokenize( attribute.second, "," );
11308         // errorCodes are checked in checkCorrectness after complete reading
11309       }
11310       else if ( attribute.first == "successcodes" )
11311       {
11312         commandData.successCodes = tokenize( attribute.second, "," );
11313         // successCodes are checked in checkCorrectness after complete reading
11314       }
11315     }
11316 
11317     std::string name;
11318     for ( auto child : children )
11319     {
11320       std::string value = child->Value();
11321       if ( value == "param" )
11322       {
11323         std::pair<bool, ParamData> result = readCommandsCommandParam( child, commandData.params );
11324         if ( result.first )
11325         {
11326           commandData.params.push_back( result.second );
11327         }
11328       }
11329       else if ( value == "proto" )
11330       {
11331         std::tie( name, commandData.returnType ) = readCommandsCommandProto( child );
11332       }
11333     }
11334     assert( !name.empty() );
11335     checkForError( ( commandData.returnType == "VkResult" ) || commandData.errorCodes.empty(),
11336                    line,
11337                    "command <" + name + "> does not return a VkResult but specifies errorcodes" );
11338     checkForError( ( commandData.returnType == "VkResult" ) || commandData.successCodes.empty(),
11339                    line,
11340                    "command <" + name + "> does not return a VkResult but specifies successcodes" );
11341     for ( auto const & param : commandData.params )
11342     {
11343       checkForError( param.stride.empty() || isParam( param.stride, commandData.params ),
11344                      param.xmlLine,
11345                      "attribute <stride> holds an unknown value <" + param.stride + ">" );
11346     }
11347 
11348     addCommand( name, commandData );
11349   }
11350 }
11351 
readCommandsCommandParam(tinyxml2::XMLElement const * element,std::vector<ParamData> const & params)11352 std::pair<bool, VulkanHppGenerator::ParamData> VulkanHppGenerator::readCommandsCommandParam( tinyxml2::XMLElement const *   element,
11353                                                                                              std::vector<ParamData> const & params )
11354 {
11355   int                                line       = element->GetLineNum();
11356   std::map<std::string, std::string> attributes = getAttributes( element );
11357   checkAttributes( line,
11358                    attributes,
11359                    {},
11360                    { { "altlen", {} },
11361                      { "api", { "vulkan", "vulkansc" } },
11362                      { "externsync", {} },
11363                      { "len", {} },
11364                      { "noautovalidity", { "true" } },
11365                      { "objecttype", { "objectType" } },
11366                      { "optional", { "false", "true" } },
11367                      { "stride", {} },
11368                      { "validstructs", {} } } );
11369 
11370   ParamData paramData( line );
11371   for ( auto attribute : attributes )
11372   {
11373     if ( attribute.first == "altlen" )
11374     {
11375       assert( paramData.len.empty() );
11376       paramData.len = attribute.second;
11377       checkForError( altLens.find( paramData.len ) != altLens.end(), line, "attribute <altlen> holds unknown value <" + paramData.len + ">" );
11378     }
11379     else if ( attribute.first == "api" )
11380     {
11381       if ( attribute.second == "vulkansc" )
11382       {
11383         return std::make_pair( false, paramData );  // skip stuff marked as "vulkansc" !
11384       }
11385       assert( attribute.second == "vulkan" );
11386     }
11387     else if ( attribute.first == "len" )
11388     {
11389       if ( paramData.len.empty() )
11390       {
11391         checkForError( ( attribute.second == "null-terminated" ) || isParam( attribute.second, params ) || isLenByStructMember( attribute.second, params ),
11392                        line,
11393                        "attribute <len> holds an unknown value <" + attribute.second + ">" );
11394         paramData.len = attribute.second;
11395       }
11396     }
11397     else if ( attribute.first == "stride" )
11398     {
11399       paramData.stride = attribute.second;
11400     }
11401     else if ( attribute.first == "optional" )
11402     {
11403       paramData.optional = ( attribute.second == "true" );
11404     }
11405     else if ( attribute.first == "validstructs" )
11406     {
11407       std::vector<std::string> validStructs = tokenize( attribute.second, "," );
11408       for ( auto const & vs : validStructs )
11409       {
11410         checkForError( m_structures.find( vs ) != m_structures.end(), line, "unknown struct <" + vs + "> listed in attribute <validstructs>" );
11411       }
11412     }
11413   }
11414 
11415   NameData nameData;
11416   std::tie( nameData, paramData.type ) = readNameAndType( element );
11417 
11418   checkForError( m_types.find( paramData.type.type ) != m_types.end(), line, "unknown type <" + paramData.type.type + ">" );
11419   checkForError( paramData.type.prefix.empty() || ( paramData.type.prefix == "const" ) || ( paramData.type.prefix == "const struct" ) ||
11420                    ( paramData.type.prefix == "struct" ),
11421                  line,
11422                  "unexpected type prefix <" + paramData.type.prefix + ">" );
11423   checkForError( paramData.type.postfix.empty() || ( paramData.type.postfix == "*" ) || ( paramData.type.postfix == "**" ) ||
11424                    ( paramData.type.postfix == "* const *" ),
11425                  line,
11426                  "unexpected type postfix <" + paramData.type.postfix + ">" );
11427   checkForError( std::find_if( params.begin(), params.end(), [&name = nameData.name]( ParamData const & pd ) { return pd.name == name; } ) == params.end(),
11428                  line,
11429                  "command param <" + nameData.name + "> already used" );
11430   paramData.name       = nameData.name;
11431   paramData.arraySizes = nameData.arraySizes;
11432 
11433   return std::make_pair( true, paramData );
11434 }
11435 
readCommandsCommandProto(tinyxml2::XMLElement const * element)11436 std::pair<std::string, std::string> VulkanHppGenerator::readCommandsCommandProto( tinyxml2::XMLElement const * element )
11437 {
11438   int line = element->GetLineNum();
11439   checkAttributes( line, getAttributes( element ), {}, {} );
11440 
11441   auto [nameData, typeInfo] = readNameAndType( element );
11442 
11443   checkForError( nameData.name.starts_with( "vk" ), line, "name <" + nameData.name + "> does not begin with <vk>" );
11444   checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
11445   checkForError( m_types.find( typeInfo.type ) != m_types.end(), line, "unknown type <" + typeInfo.type + ">" );
11446   checkForError( typeInfo.prefix.empty(), line, "unexpected type prefix <" + typeInfo.prefix + ">" );
11447   checkForError( typeInfo.postfix.empty(), line, "unexpected type postfix <" + typeInfo.postfix + ">" );
11448   checkForError( m_commands.find( nameData.name ) == m_commands.end(), line, "command <" + nameData.name + "> already specified" );
11449 
11450   return std::make_pair( nameData.name, typeInfo.type );
11451 }
11452 
readEnums(tinyxml2::XMLElement const * element)11453 void VulkanHppGenerator::readEnums( tinyxml2::XMLElement const * element )
11454 {
11455   int                                line       = element->GetLineNum();
11456   std::map<std::string, std::string> attributes = getAttributes( element );
11457   checkAttributes( line, attributes, { { "name", {} } }, { { "bitwidth", { "64" } }, { "comment", {} }, { "type", { "bitmask", "enum" } } } );
11458   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11459 
11460   std::string bitwidth, name, type;
11461   for ( auto const & attribute : attributes )
11462   {
11463     if ( attribute.first == "bitwidth" )
11464     {
11465       bitwidth = attribute.second;
11466     }
11467     else if ( attribute.first == "name" )
11468     {
11469       name = attribute.second;
11470     }
11471     else if ( attribute.first == "type" )
11472     {
11473       type = attribute.second;
11474     }
11475   }
11476   assert( !name.empty() );
11477 
11478   if ( name == "API Constants" )
11479   {
11480     checkElements( line, children, { { "enum", false } }, {} );
11481     for ( auto const & child : children )
11482     {
11483       readEnumsConstant( child );
11484     }
11485   }
11486   else
11487   {
11488     checkElements( line, children, {}, { "comment", "enum", "unused" } );
11489     checkForError( !type.empty(), line, "enum without type" );
11490 
11491     // get the EnumData entry in enum map
11492     std::map<std::string, EnumData>::iterator enumIt = m_enums.find( name );
11493     if ( enumIt == m_enums.end() )
11494     {
11495       enumIt =
11496         std::find_if( m_enums.begin(), m_enums.end(), [&name]( std::pair<std::string, EnumData> const & enumData ) { return enumData.second.alias == name; } );
11497     }
11498     checkForError( enumIt != m_enums.end(), line, "enum <" + name + "> is not listed as enum in the types section" );
11499     checkForError( enumIt->second.values.empty(), line, "enum <" + name + "> already holds values" );
11500 
11501     // mark it as a bitmask, if it is one
11502     bool bitmask = ( type == "bitmask" );
11503     if ( bitmask )
11504     {
11505       checkForError( name.find( "FlagBits" ) != std::string::npos, line, "bitmask <" + name + "> does not contain <FlagBits>" );
11506     }
11507     enumIt->second.isBitmask = bitmask;
11508     enumIt->second.bitwidth  = bitwidth;
11509 
11510     // read the names of the enum values
11511     for ( auto child : children )
11512     {
11513       std::string value = child->Value();
11514       if ( value == "comment" )
11515       {
11516         readComment( child );
11517       }
11518       else if ( value == "enum" )
11519       {
11520         readEnumsEnum( child, enumIt );
11521       }
11522     }
11523   }
11524 }
11525 
readEnumsConstant(tinyxml2::XMLElement const * element)11526 void VulkanHppGenerator::readEnumsConstant( tinyxml2::XMLElement const * element )
11527 {
11528   int                                line       = element->GetLineNum();
11529   std::map<std::string, std::string> attributes = getAttributes( element );
11530   checkAttributes( line, attributes, { { "name", {} } }, { { "alias", {} }, { "comment", {} }, { "type", {} }, { "value", {} } } );
11531   checkElements( line, getChildElements( element ), {} );
11532 
11533   std::string alias, name, value;
11534   for ( auto const & attribute : attributes )
11535   {
11536     if ( attribute.first == "alias" )
11537     {
11538       checkForError( m_constants.find( attribute.second ) != m_constants.end(), line, "unknown enum constant alias <" + attribute.second + ">" );
11539       alias = attribute.second;
11540     }
11541     else if ( attribute.first == "name" )
11542     {
11543       checkForError( m_constants.find( attribute.second ) == m_constants.end(), line, "already specified enum constant <" + attribute.second + ">" );
11544       name = attribute.second;
11545     }
11546     else if ( attribute.first == "value" )
11547     {
11548       checkForError( !attribute.second.empty(), line, "value of enum constant is empty" );
11549       value = attribute.second;
11550     }
11551   }
11552   checkForError( alias.empty() != value.empty(), line, "for enum <" + name + "> either alias or value need to be specified" );
11553   m_constants[name] = alias.empty() ? value : m_constants[alias];
11554 }
11555 
readEnumsEnum(tinyxml2::XMLElement const * element,std::map<std::string,EnumData>::iterator enumIt)11556 void VulkanHppGenerator::readEnumsEnum( tinyxml2::XMLElement const * element, std::map<std::string, EnumData>::iterator enumIt )
11557 {
11558   int                                line       = element->GetLineNum();
11559   std::map<std::string, std::string> attributes = getAttributes( element );
11560   if ( attributes.find( "alias" ) != attributes.end() )
11561   {
11562     checkAttributes( line, attributes, { { "alias", {} }, { "name", {} } }, { { "api", { "vulkan", "vulkansc" } }, { "comment", {} } } );
11563     checkElements( line, getChildElements( element ), {} );
11564 
11565     std::string alias, bitpos, name, value;
11566     for ( auto const & attribute : attributes )
11567     {
11568       if ( attribute.first == "alias" )
11569       {
11570         alias = attribute.second;
11571       }
11572       else if ( attribute.first == "api" )
11573       {
11574         if ( attribute.second == "vulkansc" )
11575         {
11576           return;  // skip stuff marked as "vulkansc" !
11577         }
11578         assert( attribute.second == "vulkan" );
11579       }
11580       else if ( attribute.first == "name" )
11581       {
11582         name = attribute.second;
11583       }
11584     }
11585     assert( !name.empty() );
11586 
11587     enumIt->second.addEnumAlias( line, name, alias );
11588   }
11589   else
11590   {
11591     checkAttributes( line, attributes, { { "name", {} } }, { { "bitpos", {} }, { "comment", {} }, { "value", {} } } );
11592     checkElements( line, getChildElements( element ), {} );
11593 
11594     std::string alias, bitpos, name, protect, value;
11595     for ( auto const & attribute : attributes )
11596     {
11597       if ( attribute.first == "bitpos" )
11598       {
11599         bitpos = attribute.second;
11600       }
11601       else if ( attribute.first == "name" )
11602       {
11603         name = attribute.second;
11604       }
11605       else if ( attribute.first == "value" )
11606       {
11607         value = attribute.second;
11608       }
11609     }
11610 
11611     std::string prefix = generateEnumSuffixes( enumIt->first, enumIt->second.isBitmask, m_tags ).first;
11612     checkForError( name.starts_with( prefix ), line, "encountered enum value <" + name + "> that does not begin with expected prefix <" + prefix + ">" );
11613 
11614     checkForError( bitpos.empty() ^ value.empty(), line, "invalid set of attributes for enum <" + name + ">" );
11615     enumIt->second.addEnumValue( line, name, protect, !bitpos.empty(), "" );
11616   }
11617 }
11618 
readComment(tinyxml2::XMLElement const * element)11619 std::string VulkanHppGenerator::readComment( tinyxml2::XMLElement const * element )
11620 {
11621   int line = element->GetLineNum();
11622   checkAttributes( line, getAttributes( element ), {}, {} );
11623   checkElements( line, getChildElements( element ), {} );
11624 
11625   return element->GetText();
11626 }
11627 
readExtensions(tinyxml2::XMLElement const * element)11628 void VulkanHppGenerator::readExtensions( tinyxml2::XMLElement const * element )
11629 {
11630   int line = element->GetLineNum();
11631   checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
11632   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11633   checkElements( line, children, { { "extension", false } } );
11634 
11635   for ( auto child : children )
11636   {
11637     assert( child->Value() == std::string( "extension" ) );
11638     readExtensionsExtension( child );
11639   }
11640 }
11641 
readExtensionsExtension(tinyxml2::XMLElement const * element)11642 void VulkanHppGenerator::readExtensionsExtension( tinyxml2::XMLElement const * element )
11643 {
11644   int                                       line       = element->GetLineNum();
11645   std::map<std::string, std::string>        attributes = getAttributes( element );
11646   std::vector<tinyxml2::XMLElement const *> children   = getChildElements( element );
11647 
11648   checkAttributes( line,
11649                    attributes,
11650                    { { "name", {} }, { "number", {} }, { "supported", { "disabled", "vulkan", "vulkansc" } } },
11651                    { { "author", {} },
11652                      { "comment", {} },
11653                      { "contact", {} },
11654                      { "depends", {} },
11655                      { "deprecatedby", {} },
11656                      { "obsoletedby", {} },
11657                      { "platform", {} },
11658                      { "promotedto", {} },
11659                      { "provisional", { "true" } },
11660                      { "requires", {} },
11661                      { "requiresCore", {} },
11662                      { "sortorder", { "1" } },
11663                      { "specialuse", { "cadsupport", "d3demulation", "debugging", "devtools", "glemulation" } },
11664                      { "type", { "device", "instance" } } } );
11665   checkElements( line, children, { { "require", false } } );
11666 
11667   std::string              deprecatedBy, name, number, obsoletedBy, platform, promotedTo;
11668   std::vector<std::string> depends;
11669   bool                     supported = false;
11670   for ( auto const & attribute : attributes )
11671   {
11672     if ( attribute.first == "deprecatedby" )
11673     {
11674       deprecatedBy = attribute.second;
11675     }
11676     else if ( attribute.first == "name" )
11677     {
11678       name = attribute.second;
11679       checkForError( m_extensions.find( name ) == m_extensions.end(), line, "already encountered extension <" + name + ">" );
11680     }
11681     else if ( attribute.first == "number" )
11682     {
11683       number = attribute.second;
11684     }
11685     else if ( attribute.first == "obsoletedby" )
11686     {
11687       obsoletedBy = attribute.second;
11688     }
11689     else if ( attribute.first == "platform" )
11690     {
11691       platform = attribute.second;
11692       checkForError( m_platforms.find( platform ) != m_platforms.end(), line, "unknown platform <" + platform + ">" );
11693     }
11694     else if ( attribute.first == "promotedto" )
11695     {
11696       promotedTo = attribute.second;
11697     }
11698     else if ( attribute.first == "provisional" )
11699     {
11700       if ( platform.empty() )
11701       {
11702         // for now, having the attribute provisional="true" implies attribute platform="provisional" to get
11703         // stuff protected by VK_ENABLE_BETA_EXTENSIONS
11704         platform = "provisional";
11705       }
11706       checkForError( platform == "provisional",
11707                      line,
11708                      "while attribute <provisional> is set to \"true\", attribute <platform> is not set to \"provisional\" but to \"" + platform + "\"" );
11709     }
11710     else if ( ( attribute.first == "depends" ) || ( attribute.first == "requires" ) )
11711     {
11712       // we don't care about the logical implications of ',' and '+' here, we're just interested to get the depends strings
11713       depends = tokenizeAny( attribute.second, ",+" );
11714     }
11715     else if ( attribute.first == "requiresCore" )
11716     {
11717       std::string const & requiresCore = attribute.second;
11718       checkForError( std::find_if( m_features.begin(),
11719                                    m_features.end(),
11720                                    [&requiresCore]( std::pair<std::string, FeatureData> const & feature )
11721                                    { return feature.second.number == requiresCore; } ) != m_features.end(),
11722                      line,
11723                      "unknown feature number <" + attribute.second + ">" );
11724     }
11725     else if ( attribute.first == "supported" )
11726     {
11727       std::vector<std::string> api = tokenize( attribute.second, "," );
11728       supported                    = ( std::find( api.begin(), api.end(), "vulkan" ) != api.end() );
11729     }
11730   }
11731 
11732   auto extensionIt = m_extensions.end();
11733   if ( supported )
11734   {
11735     extensionIt = m_extensions.insert( std::make_pair( name, ExtensionData( line, deprecatedBy, number, obsoletedBy, platform, promotedTo ) ) ).first;
11736     for ( auto const & d : depends )
11737     {
11738       checkForError( extensionIt->second.depends.insert( d ).second, line, "required depends <" + d + "> already listed" );
11739     }
11740 
11741     // extract the tag from the name, which is supposed to look like VK_<tag>_<other>
11742     size_t tagStart = name.find( '_' );
11743     checkForError( tagStart != std::string::npos, line, "name <" + name + "> is missing an underscore '_'" );
11744     size_t tagEnd = name.find( '_', tagStart + 1 );
11745     checkForError( tagEnd != std::string::npos, line, "name <" + name + "> is missing an underscore '_'" );
11746     std::string tag = name.substr( tagStart + 1, tagEnd - tagStart - 1 );
11747     checkForError( m_tags.find( tag ) != m_tags.end(), line, "name <" + name + "> is using an unknown tag <" + tag + ">" );
11748   }
11749 
11750   for ( auto child : children )
11751   {
11752     assert( child->Value() == std::string( "require" ) );
11753     if ( supported )
11754     {
11755       readExtensionsExtensionRequire( child, extensionIt );
11756     }
11757     else
11758     {
11759       readExtensionsExtensionRequireSkipped( child );
11760     }
11761   }
11762 }
11763 
readExtensionsExtensionRequire(tinyxml2::XMLElement const * element,std::map<std::string,ExtensionData>::iterator extensionIt)11764 void VulkanHppGenerator::readExtensionsExtensionRequire( tinyxml2::XMLElement const * element, std::map<std::string, ExtensionData>::iterator extensionIt )
11765 {
11766   int                                line       = element->GetLineNum();
11767   std::map<std::string, std::string> attributes = getAttributes( element );
11768   checkAttributes( line, attributes, {}, { { "depends", {} }, { "extension", {} }, { "feature", {} } } );
11769   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11770   checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
11771 
11772   std::vector<std::string> depends;
11773   for ( auto const & attribute : attributes )
11774   {
11775     if ( ( attribute.first == "depends" ) || ( attribute.first == "extension" ) )
11776     {
11777       assert( depends.empty() );
11778       depends = tokenizeAny( attribute.second, ",+" );
11779       for ( auto const & d : depends )
11780       {
11781         checkForError( std::find_if( extensionIt->second.requireData.begin(),
11782                                      extensionIt->second.requireData.end(),
11783                                      [&d]( RequireData const & rd ) { return std::find( rd.depends.begin(), rd.depends.end(), d ) != rd.depends.end(); } ) ==
11784                          extensionIt->second.requireData.end(),
11785                        line,
11786                        "required extension <" + d + "> already listed" );
11787       }
11788     }
11789     else
11790     {
11791       assert( attribute.first == "feature" );
11792       if ( m_features.find( attribute.second ) != m_features.end() )
11793       {
11794         assert( depends.empty() );
11795         depends.push_back( attribute.second );
11796       }
11797       else
11798       {
11799         checkForError( m_skippedFeatures.find( attribute.second ) != m_skippedFeatures.end(), line, "unknown feature <" + attribute.second + ">" );
11800         readExtensionsExtensionRequireSkipped( element );
11801         return;
11802       }
11803     }
11804   }
11805 
11806   RequireData requireData( line, depends );
11807   bool        requireDataEmpty = true;
11808   for ( auto child : children )
11809   {
11810     std::string value = child->Value();
11811     if ( value == "command" )
11812     {
11813       readExtensionsExtensionRequireCommand( child, extensionIt->first, requireData );
11814       requireDataEmpty = false;
11815     }
11816     else if ( value == "comment" )
11817     {
11818       readComment( child );
11819     }
11820     else if ( value == "enum" )
11821     {
11822       readRequireEnum( child, extensionIt->first );
11823     }
11824     else if ( value == "type" )
11825     {
11826       readExtensionsExtensionRequireType( child, extensionIt->first, requireData );
11827       requireDataEmpty = false;
11828     }
11829   }
11830   if ( !requireDataEmpty )
11831   {
11832     extensionIt->second.requireData.push_back( requireData );
11833   }
11834 }
11835 
readExtensionsExtensionRequireCommand(tinyxml2::XMLElement const * element,std::string const & extensionName,RequireData & requireData)11836 void VulkanHppGenerator::readExtensionsExtensionRequireCommand( tinyxml2::XMLElement const * element,
11837                                                                 std::string const &          extensionName,
11838                                                                 RequireData &                requireData )
11839 {
11840   int                                line       = element->GetLineNum();
11841   std::map<std::string, std::string> attributes = getAttributes( element );
11842   checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
11843   checkElements( line, getChildElements( element ), {} );
11844 
11845   std::string name;
11846   for ( auto const & attribute : attributes )
11847   {
11848     if ( attribute.first == "name" )
11849     {
11850       name = attribute.second;
11851     }
11852   }
11853   assert( !name.empty() );
11854 
11855   // mark this command be part of this extension
11856   auto commandIt = m_commands.find( name );
11857   checkForError(
11858     commandIt != m_commands.end(), line, "command <" + name + "> marked as required in extension <" + extensionName + "> was not listed before as a command!" );
11859   if ( commandIt->second.referencedIn.empty() )
11860   {
11861     commandIt->second.referencedIn = extensionName;
11862   }
11863   else
11864   {
11865     checkForError( getPlatform( commandIt->second.referencedIn ) == getPlatform( extensionName ),
11866                    line,
11867                    "command <" + name + "> is referenced in extensions <" + commandIt->second.referencedIn + "> and <" + extensionName +
11868                      "> and thus protected by different platforms <" + getPlatform( commandIt->second.referencedIn ) + "> and <" +
11869                      getPlatform( extensionName ) + ">!" );
11870   }
11871   assert( std::find( requireData.commands.begin(), requireData.commands.end(), name ) == requireData.commands.end() );
11872   requireData.commands.push_back( name );
11873 }
11874 
readExtensionsExtensionRequireSkipped(tinyxml2::XMLElement const * element)11875 void VulkanHppGenerator::readExtensionsExtensionRequireSkipped( tinyxml2::XMLElement const * element )
11876 {
11877   int                                line       = element->GetLineNum();
11878   std::map<std::string, std::string> attributes = getAttributes( element );
11879   checkAttributes( line, attributes, {}, { { "comment", {} }, { "depends", {} }, { "extension", {} }, { "feature", {} } } );
11880   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11881   checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
11882 
11883   for ( auto child : children )
11884   {
11885     std::string value = child->Value();
11886     if ( value == "command" )
11887     {
11888       readRequireCommandSkipped( child );
11889     }
11890     else if ( value == "type" )
11891     {
11892       readRequireTypeSkipped( child );
11893     }
11894   }
11895 }
11896 
readExtensionsExtensionRequireType(tinyxml2::XMLElement const * element,std::string const & extensionName,RequireData & requireData)11897 void VulkanHppGenerator::readExtensionsExtensionRequireType( tinyxml2::XMLElement const * element,
11898                                                              std::string const &          extensionName,
11899                                                              RequireData &                requireData )
11900 {
11901   int                                line       = element->GetLineNum();
11902   std::map<std::string, std::string> attributes = getAttributes( element );
11903   checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
11904   checkElements( line, getChildElements( element ), {} );
11905 
11906   std::string name;
11907   for ( auto const & attribute : attributes )
11908   {
11909     if ( attribute.first == "name" )
11910     {
11911       name = attribute.second;
11912     }
11913   }
11914   assert( !name.empty() );
11915 
11916   auto typeIt = m_types.find( name );
11917   checkForError( typeIt != m_types.end(), line, "failed to find required type <" + name + ">" );
11918   if ( typeIt->second.referencedIn.empty() )
11919   {
11920     typeIt->second.referencedIn = extensionName;
11921     assert( std::find( requireData.types.begin(), requireData.types.end(), name ) == requireData.types.end() );
11922     requireData.types.push_back( name );
11923   }
11924   else
11925   {
11926     checkForError( getPlatform( typeIt->second.referencedIn ) == getPlatform( extensionName ),
11927                    line,
11928                    "type <" + name + "> is referenced in extensions <" + typeIt->second.referencedIn + "> and <" + extensionName +
11929                      "> and thus protected by different platforms <" + getPlatform( typeIt->second.referencedIn ) + "> and <" + getPlatform( extensionName ) +
11930                      ">!" );
11931   }
11932 }
11933 
readFeature(tinyxml2::XMLElement const * element)11934 void VulkanHppGenerator::readFeature( tinyxml2::XMLElement const * element )
11935 {
11936   int                                line       = element->GetLineNum();
11937   std::map<std::string, std::string> attributes = getAttributes( element );
11938   checkAttributes( line, attributes, { { "api", { "vulkan", "vulkansc" } }, { "comment", {} }, { "name", {} }, { "number", {} } }, {} );
11939   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11940   checkElements( line, children, { { "require", false } }, { "remove" } );
11941 
11942   std::string name, number, modifiedNumber;
11943   for ( auto const & attribute : attributes )
11944   {
11945     if ( attribute.first == "name" )
11946     {
11947       name = attribute.second;
11948     }
11949     else if ( attribute.first == "number" )
11950     {
11951       number         = attribute.second;
11952       modifiedNumber = number;
11953       std::replace( modifiedNumber.begin(), modifiedNumber.end(), '.', '_' );
11954     }
11955   }
11956   assert( !name.empty() && !number.empty() );
11957 
11958   auto attributeIt = attributes.find( "api" );
11959   assert( attributeIt != attributes.end() );
11960   std::vector<std::string> api = tokenize( attributeIt->second, "," );
11961   if ( std::find( api.begin(), api.end(), "vulkan" ) != api.end() )
11962   {
11963     checkForError( name == "VK_VERSION_" + modifiedNumber, line, "unexpected formatting of name <" + name + ">" );
11964     checkForError( m_features.find( name ) == m_features.end(), line, "already specified feature <" + name + ">" );
11965     assert( m_skippedFeatures.find( name ) == m_skippedFeatures.end() );
11966 
11967     auto featureIt = m_features.insert( std::make_pair( name, number ) ).first;
11968     for ( auto child : children )
11969     {
11970       std::string value = child->Value();
11971       if ( value == "remove" )
11972       {
11973         checkForError( false, line, "unsupported child <remove>: should be filtered by attribute <api>" );
11974       }
11975       else if ( value == "require" )
11976       {
11977         readFeatureRequire( child, featureIt );
11978       }
11979     }
11980   }
11981   else
11982   {
11983     // skip this feature
11984     checkForError( name == "VKSC_VERSION_" + modifiedNumber, line, "unexpected formatting of name <" + name + ">" );
11985     checkForError( m_skippedFeatures.insert( name ).second, line, "already specified skipped feature <" + name + ">" );
11986     assert( m_features.find( name ) == m_features.end() );
11987 
11988     for ( auto child : children )
11989     {
11990       std::string value = child->Value();
11991       if ( value == "require" )
11992       {
11993         readFeatureRequireSkipped( child );
11994       }
11995     }
11996   }
11997 }
11998 
readFeatureRequire(tinyxml2::XMLElement const * element,std::map<std::string,FeatureData>::iterator featureIt)11999 void VulkanHppGenerator::readFeatureRequire( tinyxml2::XMLElement const * element, std::map<std::string, FeatureData>::iterator featureIt )
12000 {
12001   int line = element->GetLineNum();
12002   checkAttributes( line, getAttributes( element ), {}, { { "comment", {} } } );
12003   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12004   checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
12005 
12006   RequireData requireData( line, { "" } );
12007   bool        requireDataEmpty = true;
12008   for ( auto child : children )
12009   {
12010     std::string value = child->Value();
12011     if ( value == "command" )
12012     {
12013       readFeatureRequireCommand( child, featureIt, requireData );
12014       requireDataEmpty = false;
12015     }
12016     else if ( value == "comment" )
12017     {
12018       readComment( child );
12019     }
12020     else if ( value == "enum" )
12021     {
12022       readRequireEnum( child, "" );
12023     }
12024     else if ( value == "type" )
12025     {
12026       readFeatureRequireType( child, featureIt, requireData );
12027       requireDataEmpty = false;
12028     }
12029   }
12030   if ( !requireDataEmpty )
12031   {
12032     featureIt->second.requireData.push_back( requireData );
12033   }
12034 }
12035 
readFeatureRequireCommandSkipped(tinyxml2::XMLElement const * element)12036 void VulkanHppGenerator::readFeatureRequireCommandSkipped( tinyxml2::XMLElement const * element )
12037 {
12038   int                                line       = element->GetLineNum();
12039   std::map<std::string, std::string> attributes = getAttributes( element );
12040   checkAttributes( line, attributes, {}, { { "name", {} } } );
12041 
12042   std::string name = attributes.find( "name" )->second;
12043 
12044   auto commandIt = m_commands.find( name );
12045   checkForError( commandIt != m_commands.end(), line, "unknown required command <" + name + ">" );
12046   checkForError( commandIt->second.referencedIn.empty(), line, "command <" + name + "> already listed with feature <" + commandIt->second.referencedIn + ">" );
12047 
12048   m_commands.erase( commandIt );
12049 }
12050 
readFeatureRequireCommand(tinyxml2::XMLElement const * element,std::map<std::string,FeatureData>::iterator featureIt,RequireData & requireData)12051 void VulkanHppGenerator::readFeatureRequireCommand( tinyxml2::XMLElement const *                 element,
12052                                                     std::map<std::string, FeatureData>::iterator featureIt,
12053                                                     RequireData &                                requireData )
12054 {
12055   int                                line       = element->GetLineNum();
12056   std::map<std::string, std::string> attributes = getAttributes( element );
12057   checkAttributes( line, attributes, {}, { { "name", {} } } );
12058 
12059   std::string name = attributes.find( "name" )->second;
12060 
12061   auto commandIt = m_commands.find( name );
12062   checkForError( commandIt != m_commands.end(), line, "feature <" + featureIt->first + "> requires unknown command <" + name + ">" );
12063   checkForError( commandIt->second.referencedIn.empty(), line, "command <" + name + "> already listed with feature <" + commandIt->second.referencedIn + ">" );
12064 
12065   commandIt->second.referencedIn = featureIt->first;
12066 
12067   assert( std::find( requireData.commands.begin(), requireData.commands.end(), name ) == requireData.commands.end() );
12068   requireData.commands.push_back( name );
12069 }
12070 
readFeatureRequireSkipped(tinyxml2::XMLElement const * element)12071 void VulkanHppGenerator::readFeatureRequireSkipped( tinyxml2::XMLElement const * element )
12072 {
12073   int line = element->GetLineNum();
12074   checkAttributes( line, getAttributes( element ), {}, { { "comment", {} } } );
12075   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12076   checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
12077 
12078   for ( auto child : children )
12079   {
12080     std::string value = child->Value();
12081     if ( value == "command" )
12082     {
12083       readFeatureRequireCommandSkipped( child );
12084     }
12085     else if ( value == "enum" )
12086     {
12087       readRequireEnumSkipped( child );
12088     }
12089     else if ( value == "type" )
12090     {
12091       readRequireTypeSkipped( child );
12092     }
12093   }
12094 }
12095 
readFeatureRequireType(tinyxml2::XMLElement const * element,std::map<std::string,FeatureData>::iterator featureIt,RequireData & requireData)12096 void VulkanHppGenerator::readFeatureRequireType( tinyxml2::XMLElement const *                 element,
12097                                                  std::map<std::string, FeatureData>::iterator featureIt,
12098                                                  RequireData &                                requireData )
12099 {
12100   int                                line       = element->GetLineNum();
12101   std::map<std::string, std::string> attributes = getAttributes( element );
12102   checkAttributes( line, attributes, {}, { { "comment", {} }, { "name", {} } } );
12103   checkElements( line, getChildElements( element ), {} );
12104 
12105   std::string name          = attributes.find( "name" )->second;
12106   auto        requireTypeIt = std::find_if( requireData.types.begin(), requireData.types.end(), [&name]( std::string const & type ) { return type == name; } );
12107   checkForError( requireTypeIt == requireData.types.end(), line, "type <" + name + "> already listed for this feature!" );
12108 
12109   // some types are in fact includes (like vk_platform) or defines (like VK_API_VERSION)
12110   if ( ( m_defines.find( name ) == m_defines.end() ) && ( m_includes.find( name ) == m_includes.end() ) )
12111   {
12112     auto typeIt = m_types.find( name );
12113     checkForError( typeIt != m_types.end(), line, "feature <" + featureIt->first + "> requires unknown type <" + name + ">" );
12114     checkForError( typeIt->second.referencedIn.empty() || ( typeIt->second.referencedIn == featureIt->first ),
12115                    line,
12116                    "type <" + name + "> already listed on feature <" + typeIt->second.referencedIn + ">" );
12117     typeIt->second.referencedIn = featureIt->first;
12118 
12119     requireData.types.push_back( name );
12120   }
12121 }
12122 
readFormats(tinyxml2::XMLElement const * element)12123 void VulkanHppGenerator::readFormats( tinyxml2::XMLElement const * element )
12124 {
12125   int line = element->GetLineNum();
12126   checkAttributes( line, getAttributes( element ), {}, {} );
12127   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12128   checkElements( line, children, { { "format", false } } );
12129 
12130   for ( auto child : children )
12131   {
12132     readFormatsFormat( child );
12133   }
12134 }
12135 
readFormatsFormat(tinyxml2::XMLElement const * element)12136 void VulkanHppGenerator::readFormatsFormat( tinyxml2::XMLElement const * element )
12137 {
12138   int                                line       = element->GetLineNum();
12139   std::map<std::string, std::string> attributes = getAttributes( element );
12140   checkAttributes( line,
12141                    attributes,
12142                    { { "blockSize", { "1", "2", "3", "4", "5", "6", "8", "12", "16", "24", "32" } },
12143                      { "class", {} },
12144                      { "name", {} },
12145                      { "texelsPerBlock", { "1", "16", "20", "25", "30", "36", "40", "48", "50", "60", "64", "80", "100", "120", "144" } } },
12146                    { { "blockExtent", { "1", "2", "4", "5", "6", "8", "10", "12" } },
12147                      { "chroma", { "420", "422", "444" } },
12148                      { "compressed", { "ASTC HDR", "ASTC LDR", "BC", "EAC", "ETC", "ETC2", "PVRTC" } },
12149                      { "packed", { "8", "16", "32" } } } );
12150   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12151   checkElements( line, children, { { "component", false } }, { "plane", "spirvimageformat" } );
12152 
12153   FormatData  format( line );
12154   std::string name;
12155   for ( auto const & attribute : attributes )
12156   {
12157     if ( attribute.first == "blockExtent" )
12158     {
12159       checkForError( tokenize( attribute.second, "," ).size() == 3, line, "unexpected number of elements in attribute <blockExtent>" );
12160       format.blockExtent = attribute.second;
12161     }
12162     if ( attribute.first == "blockSize" )
12163     {
12164       format.blockSize = attribute.second;
12165     }
12166     else if ( attribute.first == "chroma" )
12167     {
12168       format.chroma = attribute.second;
12169     }
12170     else if ( attribute.first == "class" )
12171     {
12172       format.classAttribute = attribute.second;
12173     }
12174     else if ( attribute.first == "compressed" )
12175     {
12176       format.compressed = attribute.second;
12177     }
12178     else if ( attribute.first == "name" )
12179     {
12180       name = attribute.second;
12181     }
12182     else if ( attribute.first == "packed" )
12183     {
12184       format.packed = attribute.second;
12185     }
12186     else if ( attribute.first == "texelsPerBlock" )
12187     {
12188       format.texelsPerBlock = attribute.second;
12189     }
12190   }
12191 
12192   auto formatIt = m_enums.find( "VkFormat" );
12193   assert( formatIt != m_enums.end() );
12194 
12195   checkForError( std::find_if( formatIt->second.values.begin(),
12196                                formatIt->second.values.end(),
12197                                [&name]( EnumValueData const & evd ) { return evd.name == name; } ) != formatIt->second.values.end() ||
12198                    ( formatIt->second.aliases.find( name ) != formatIt->second.aliases.end() ),
12199                  line,
12200                  "encountered unknown format <" + name + ">" );
12201   auto [it, inserted] = m_formats.insert( std::make_pair( name, format ) );
12202   checkForError( inserted, line, "format <" + name + "> already specified on line " + std::to_string( it->second.xmlLine ) );
12203 
12204   for ( auto child : children )
12205   {
12206     std::string value = child->Value();
12207     if ( value == "component" )
12208     {
12209       readFormatsFormatComponent( child, it->second );
12210     }
12211     else if ( value == "plane" )
12212     {
12213       readFormatsFormatPlane( child, it->second );
12214     }
12215     else if ( value == "spirvimageformat" )
12216     {
12217       readFormatsFormatSPIRVImageFormat( child, it->second );
12218     }
12219   }
12220 
12221   if ( it->second.components.front().bits == "compressed" )
12222   {
12223     for ( auto componentIt = std::next( it->second.components.begin() ); componentIt != it->second.components.end(); ++componentIt )
12224     {
12225       checkForError( componentIt->bits == "compressed", line, "component is expected to be marked as compressed in attribute <bits>" );
12226     }
12227   }
12228   if ( !it->second.components.front().planeIndex.empty() )
12229   {
12230     for ( auto componentIt = std::next( it->second.components.begin() ); componentIt != it->second.components.end(); ++componentIt )
12231     {
12232       checkForError( !componentIt->planeIndex.empty(), line, "component is expected to have a planeIndex" );
12233     }
12234     size_t planeCount = 1 + std::stoi( it->second.components.back().planeIndex );
12235     checkForError( it->second.planes.size() == planeCount, line, "number of planes does not fit to largest planeIndex of the components" );
12236   }
12237 }
12238 
readFormatsFormatComponent(tinyxml2::XMLElement const * element,FormatData & formatData)12239 void VulkanHppGenerator::readFormatsFormatComponent( tinyxml2::XMLElement const * element, FormatData & formatData )
12240 {
12241   int                                line       = element->GetLineNum();
12242   std::map<std::string, std::string> attributes = getAttributes( element );
12243   checkAttributes( line,
12244                    attributes,
12245                    { { "bits", { "1", "2", "4", "5", "6", "8", "9", "10", "11", "12", "16", "24", "32", "64", "compressed" } },
12246                      { "name", {} },
12247                      { "numericFormat", { "SFLOAT", "SINT", "SNORM", "SRGB", "SSCALED", "UFLOAT", "UINT", "UNORM", "USCALED" } } },
12248                    { { "planeIndex", { "0", "1", "2" } } } );
12249   checkElements( line, getChildElements( element ), {} );
12250 
12251   formatData.components.emplace_back( line );
12252   ComponentData & component = formatData.components.back();
12253   for ( auto const & attribute : attributes )
12254   {
12255     if ( attribute.first == "bits" )
12256     {
12257       checkForError(
12258         ( attribute.second != "compressed" ) || !formatData.compressed.empty(), line, "component of a not compressed format is marked as compressed" );
12259       component.bits = attribute.second;
12260     }
12261     else if ( attribute.first == "name" )
12262     {
12263       component.name = attribute.second;
12264     }
12265     else if ( attribute.first == "numericFormat" )
12266     {
12267       component.numericFormat = attribute.second;
12268     }
12269     else if ( attribute.first == "planeIndex" )
12270     {
12271       component.planeIndex = attribute.second;
12272     }
12273   }
12274 }
12275 
readFormatsFormatPlane(tinyxml2::XMLElement const * element,FormatData & formatData)12276 void VulkanHppGenerator::readFormatsFormatPlane( tinyxml2::XMLElement const * element, FormatData & formatData )
12277 {
12278   int                                line       = element->GetLineNum();
12279   std::map<std::string, std::string> attributes = getAttributes( element );
12280   checkAttributes(
12281     line, attributes, { { "compatible", {} }, { "index", { "0", "1", "2" } }, { "heightDivisor", { "1", "2" } }, { "widthDivisor", { "1", "2" } } }, {} );
12282   checkElements( line, getChildElements( element ), {} );
12283 
12284   formatData.planes.emplace_back( line );
12285   PlaneData & plane = formatData.planes.back();
12286   for ( auto const & attribute : attributes )
12287   {
12288     if ( attribute.first == "compatible" )
12289     {
12290       plane.compatible = attribute.second;
12291       auto formatIt    = m_enums.find( "VkFormat" );
12292       assert( formatIt != m_enums.end() );
12293       checkForError( std::find_if( formatIt->second.values.begin(),
12294                                    formatIt->second.values.end(),
12295                                    [&plane]( EnumValueData const & evd ) { return evd.name == plane.compatible; } ) != formatIt->second.values.end(),
12296                      line,
12297                      "encountered unknown format <" + plane.compatible + ">" );
12298     }
12299     else if ( attribute.first == "index" )
12300     {
12301       size_t index = std::stoi( attribute.second );
12302       checkForError( index + 1 == formatData.planes.size(), line, "unexpected index <" + attribute.second + ">" );
12303     }
12304     else if ( attribute.first == "heightDivisor" )
12305     {
12306       plane.heightDivisor = attribute.second;
12307     }
12308     else if ( attribute.first == "widthDivisor" )
12309     {
12310       plane.widthDivisor = attribute.second;
12311     }
12312   }
12313 }
12314 
readFormatsFormatSPIRVImageFormat(tinyxml2::XMLElement const * element,FormatData & formatData)12315 void VulkanHppGenerator::readFormatsFormatSPIRVImageFormat( tinyxml2::XMLElement const * element, FormatData & formatData )
12316 {
12317   int                                line       = element->GetLineNum();
12318   std::map<std::string, std::string> attributes = getAttributes( element );
12319   checkAttributes( line, attributes, { { "name", {} } }, {} );
12320   checkElements( line, getChildElements( element ), {} );
12321 
12322   for ( auto const & attribute : attributes )
12323   {
12324     assert( attribute.first == "name" );
12325     checkForError( formatData.spirvImageFormat.empty(), line, "spirvimageformat <" + attribute.second + "> already specified" );
12326     formatData.spirvImageFormat = attribute.second;
12327   }
12328 }
12329 
readNameAndType(tinyxml2::XMLElement const * element)12330 std::pair<VulkanHppGenerator::NameData, VulkanHppGenerator::TypeInfo> VulkanHppGenerator::readNameAndType( tinyxml2::XMLElement const * element )
12331 {
12332   int                                       line     = element->GetLineNum();
12333   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12334   checkElements( line, children, { { "name", true } }, { { "enum" }, { "type" } } );
12335 
12336   NameData nameData;
12337   TypeInfo typeInfo;
12338   for ( auto child : children )
12339   {
12340     line = child->GetLineNum();
12341     checkAttributes( line, getAttributes( child ), {}, {} );
12342     checkElements( line, getChildElements( child ), {} );
12343 
12344     std::string value = child->Value();
12345     if ( value == "enum" )
12346     {
12347       nameData.arraySizes.push_back( child->GetText() );
12348       checkForError( child->PreviousSibling() && ( strcmp( child->PreviousSibling()->Value(), "[" ) == 0 ) && child->NextSibling() &&
12349                        ( strcmp( child->NextSibling()->Value(), "]" ) == 0 ),
12350                      line,
12351                      std::string( "array specifiation is ill-formatted: <" ) + nameData.arraySizes.back() + ">" );
12352       checkForError(
12353         m_constants.find( nameData.arraySizes.back() ) != m_constants.end(), line, "using unknown enum value <" + nameData.arraySizes.back() + ">" );
12354     }
12355     else if ( value == "name" )
12356     {
12357       nameData.name = child->GetText();
12358       std::string bitCount;
12359       std::tie( nameData.arraySizes, bitCount ) = readModifiers( child->NextSibling() );
12360       checkForError( bitCount.empty(), line, "name <" + nameData.name + "> with unsupported bitCount <" + bitCount + ">" );
12361     }
12362     else if ( value == "type" )
12363     {
12364       typeInfo = readTypeInfo( child );
12365     }
12366   }
12367   return std::make_pair( nameData, typeInfo );
12368 }
12369 
readPlatforms(tinyxml2::XMLElement const * element)12370 void VulkanHppGenerator::readPlatforms( tinyxml2::XMLElement const * element )
12371 {
12372   int line = element->GetLineNum();
12373   checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
12374   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12375   checkElements( line, children, { { "platform", false } } );
12376 
12377   for ( auto child : children )
12378   {
12379     readPlatformsPlatform( child );
12380   }
12381 }
12382 
readPlatformsPlatform(tinyxml2::XMLElement const * element)12383 void VulkanHppGenerator::readPlatformsPlatform( tinyxml2::XMLElement const * element )
12384 {
12385   int                                line       = element->GetLineNum();
12386   std::map<std::string, std::string> attributes = getAttributes( element );
12387   checkAttributes( line, attributes, { { "comment", {} }, { "name", {} }, { "protect", {} } }, {} );
12388   checkElements( line, getChildElements( element ), {} );
12389 
12390   std::string name, protect;
12391   for ( auto const & attribute : attributes )
12392   {
12393     if ( attribute.first == "name" )
12394     {
12395       name = attribute.second;
12396       checkForError( !name.empty(), line, "attribute <name> is empty" );
12397     }
12398     else if ( attribute.first == "protect" )
12399     {
12400       protect = attribute.second;
12401       checkForError( !protect.empty(), line, "attribute <protect> is empty" );
12402     }
12403   }
12404   assert( !name.empty() && !protect.empty() );
12405 
12406   checkForError( std::find_if( m_platforms.begin(),
12407                                m_platforms.end(),
12408                                [&protect]( std::pair<std::string, PlatformData> const & p ) { return p.second.protect == protect; } ) == m_platforms.end(),
12409                  line,
12410                  "platform protect <" + protect + "> already specified" );
12411   checkForError( m_platforms.insert( std::make_pair( name, PlatformData( protect ) ) ).second, line, "platform name <" + name + "> already specified" );
12412 }
12413 
readRegistry(tinyxml2::XMLElement const * element)12414 void VulkanHppGenerator::readRegistry( tinyxml2::XMLElement const * element )
12415 {
12416   int line = element->GetLineNum();
12417   checkAttributes( line, getAttributes( element ), {}, {} );
12418 
12419   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12420   checkElements( line,
12421                  children,
12422                  { { "commands", true },
12423                    { "comment", false },
12424                    { "enums", false },
12425                    { "extensions", true },
12426                    { "feature", false },
12427                    { "platforms", true },
12428                    { "spirvcapabilities", true },
12429                    { "spirvextensions", true },
12430                    { "tags", true },
12431                    { "types", true } },
12432                  { "formats" } );
12433   for ( auto child : children )
12434   {
12435     const std::string value = child->Value();
12436     if ( value == "commands" )
12437     {
12438       readCommands( child );
12439     }
12440     else if ( value == "comment" )
12441     {
12442       std::string comment = readComment( child );
12443       if ( comment.find( "\nCopyright" ) == 0 )
12444       {
12445         setVulkanLicenseHeader( child->GetLineNum(), comment );
12446       }
12447     }
12448     else if ( value == "enums" )
12449     {
12450       readEnums( child );
12451     }
12452     else if ( value == "extensions" )
12453     {
12454       readExtensions( child );
12455     }
12456     else if ( value == "feature" )
12457     {
12458       readFeature( child );
12459     }
12460     else if ( value == "formats" )
12461     {
12462       readFormats( child );
12463     }
12464     else if ( value == "platforms" )
12465     {
12466       readPlatforms( child );
12467     }
12468     else if ( value == "spirvcapabilities" )
12469     {
12470       readSPIRVCapabilities( child );
12471     }
12472     else if ( value == "spirvextensions" )
12473     {
12474       readSPIRVExtensions( child );
12475     }
12476     else if ( value == "tags" )
12477     {
12478       readTags( child );
12479     }
12480     else if ( value == "types" )
12481     {
12482       readTypes( child );
12483     }
12484   }
12485 }
12486 
readRequireCommandSkipped(tinyxml2::XMLElement const * element)12487 void VulkanHppGenerator::readRequireCommandSkipped( tinyxml2::XMLElement const * element )
12488 {
12489   int                                line       = element->GetLineNum();
12490   std::map<std::string, std::string> attributes = getAttributes( element );
12491   checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
12492   checkElements( line, getChildElements( element ), {} );
12493 
12494   std::string name = attributes.find( "name" )->second;
12495 
12496   // some commands might be skipped by multiple extensions!
12497   auto commandIt = m_commands.find( name );
12498   if ( commandIt != m_commands.end() )
12499   {
12500     checkForError( m_skippedCommands.insert( name ).second, line, "to be skipped command <" + name + "> is already marked as skipped" );
12501     m_commands.erase( commandIt );
12502   }
12503   else
12504   {
12505     checkForError( m_skippedCommands.find( name ) != m_skippedCommands.end(),
12506                    line,
12507                    "to be skipped command <" + name + "> is neither listed as command nor as skipped command" );
12508   }
12509 }
12510 
readRequireEnum(tinyxml2::XMLElement const * element,std::string const & extensionName)12511 void VulkanHppGenerator::readRequireEnum( tinyxml2::XMLElement const * element, std::string const & extensionName )
12512 {
12513   int                                line       = element->GetLineNum();
12514   std::map<std::string, std::string> attributes = getAttributes( element );
12515   if ( attributes.find( "alias" ) != attributes.end() )
12516   {
12517     checkAttributes( line, attributes, { { "alias", {} }, { "name", {} } }, { { "api", { "vulkan", "vulkansc" } }, { "comment", {} }, { "extends", {} } } );
12518     checkElements( line, getChildElements( element ), {} );
12519 
12520     std::string alias, bitpos, name, extends, extnumber, offset, value;
12521     for ( auto const & attribute : attributes )
12522     {
12523       if ( attribute.first == "alias" )
12524       {
12525         alias = attribute.second;
12526       }
12527       if ( attribute.first == "api" )
12528       {
12529         if ( attribute.second == "vulkansc" )
12530         {
12531           return;  // skip stuff marked as "vulkansc" !
12532         }
12533         assert( attribute.second == "vulkan" );
12534       }
12535       else if ( attribute.first == "extends" )
12536       {
12537         extends = attribute.second;
12538       }
12539       else if ( attribute.first == "name" )
12540       {
12541         name = attribute.second;
12542       }
12543     }
12544 
12545     if ( !extends.empty() )
12546     {
12547       auto enumIt = m_enums.find( extends );
12548       checkForError( enumIt != m_enums.end(), line, "feature extends unknown enum <" + extends + ">" );
12549 
12550       // add this enum name to the list of aliases
12551       enumIt->second.addEnumAlias( line, name, alias );
12552     }
12553   }
12554   else
12555   {
12556     checkAttributes( line,
12557                      attributes,
12558                      { { "name", {} } },
12559                      { { "api", { "vulkan", "vulkansc" } },
12560                        { "bitpos", {} },
12561                        { "comment", {} },
12562                        { "extends", {} },
12563                        { "dir", { "-" } },
12564                        { "extnumber", {} },
12565                        { "offset", {} },
12566                        { "protect", { "VK_ENABLE_BETA_EXTENSIONS" } },
12567                        { "value", {} } } );
12568     checkElements( line, getChildElements( element ), {} );
12569 
12570     std::string bitpos, name, extends, offset, protect, value;
12571     for ( auto const & attribute : attributes )
12572     {
12573       if ( attribute.first == "api" )
12574       {
12575         if ( attribute.second == "vulkansc" )
12576         {
12577           return;  // skip stuff marked as "vulkansc" !
12578         }
12579         assert( attribute.second == "vulkan" );
12580       }
12581       else if ( attribute.first == "bitpos" )
12582       {
12583         bitpos = attribute.second;
12584       }
12585       else if ( attribute.first == "extends" )
12586       {
12587         extends = attribute.second;
12588       }
12589       else if ( attribute.first == "name" )
12590       {
12591         name = attribute.second;
12592       }
12593       else if ( attribute.first == "offset" )
12594       {
12595         offset = attribute.second;
12596       }
12597       else if ( attribute.first == "protect" )
12598       {
12599         protect = attribute.second;
12600       }
12601       else if ( attribute.first == "value" )
12602       {
12603         value = attribute.second;
12604       }
12605     }
12606 
12607     if ( !extends.empty() )
12608     {
12609       auto enumIt = m_enums.find( extends );
12610       if ( enumIt == m_enums.end() )
12611       {
12612         // need to re-add a previously removed enum !!
12613         enumIt = m_skippedEnums.find( extends );
12614         checkForError( enumIt != m_skippedEnums.end(), line, "feature extends unknown enum <" + extends + ">" );
12615         enumIt = m_enums.insert( *enumIt ).first;
12616 
12617         auto typeIt = m_skippedTypes.find( extends );
12618         assert( ( m_types.find( extends ) == m_types.end() ) || ( typeIt != m_skippedTypes.end() ) );
12619         typeIt->second.referencedIn = extensionName;
12620         m_types[extends]            = typeIt->second;
12621         m_skippedTypes.erase( typeIt );
12622       }
12623 
12624       // add this enum name to the list of values
12625       checkForError( bitpos.empty() + offset.empty() + value.empty() == 2,
12626                      line,
12627                      "exactly one out of bitpos = <" + bitpos + ">, offset = <" + offset + ">, and value = <" + value + "> are supposed to be empty" );
12628       enumIt->second.addEnumValue( element->GetLineNum(), name, protect, !bitpos.empty(), extensionName );
12629     }
12630     else if ( value.empty() )
12631     {
12632       checkForError( m_constants.find( name ) != m_constants.end(), line, "unknown required enum <" + name + ">" );
12633     }
12634   }
12635 }
12636 
readRequireEnumSkipped(tinyxml2::XMLElement const * element)12637 void VulkanHppGenerator::readRequireEnumSkipped( tinyxml2::XMLElement const * element )
12638 {
12639   int                                line       = element->GetLineNum();
12640   std::map<std::string, std::string> attributes = getAttributes( element );
12641   checkAttributes( line,
12642                    attributes,
12643                    { { "name", {} } },
12644                    { { "alias", {} },
12645                      { "bitpos", {} },
12646                      { "comment", {} },
12647                      { "extends", {} },
12648                      { "dir", { "-" } },
12649                      { "extnumber", {} },
12650                      { "offset", {} },
12651                      { "protect", {} },
12652                      { "value", {} } } );
12653   checkElements( line, getChildElements( element ), {} );
12654 
12655   std::string extends, name;
12656   for ( auto const & attribute : attributes )
12657   {
12658     if ( attribute.first == "extends" )
12659     {
12660       extends = attribute.second;
12661     }
12662     else if ( attribute.first == "name" )
12663     {
12664       name = attribute.second;
12665     }
12666   }
12667   assert( !name.empty() );
12668 
12669   if ( extends == "VkResult" )
12670   {
12671     // check that the to be skipped enum value is not already listed
12672     auto enumIt = m_enums.find( extends );
12673     assert( enumIt != m_enums.end() );
12674     auto valueIt =
12675       std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&name]( EnumValueData const & evd ) { return evd.name == name; } );
12676     checkForError( valueIt == enumIt->second.values.end(),
12677                    line,
12678                    "to be skipped enum value <" + name + "> extending enum <" + extends + "> is regularly specified for that enum" );
12679 
12680     // look for all the errorCodes (and successCodes) and remove this enum value!
12681     for ( auto & command : m_commands )
12682     {
12683       auto errorCodeIt = std::find( command.second.errorCodes.begin(), command.second.errorCodes.end(), name );
12684       if ( errorCodeIt != command.second.errorCodes.end() )
12685       {
12686         command.second.errorCodes.erase( errorCodeIt );
12687       }
12688       assert( std::find( command.second.successCodes.begin(), command.second.successCodes.end(), name ) == command.second.successCodes.end() );
12689     }
12690   }
12691 }
12692 
readRequireTypeSkipped(tinyxml2::XMLElement const * element)12693 void VulkanHppGenerator::readRequireTypeSkipped( tinyxml2::XMLElement const * element )
12694 {
12695   int                                line       = element->GetLineNum();
12696   std::map<std::string, std::string> attributes = getAttributes( element );
12697   checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
12698   checkElements( line, getChildElements( element ), {} );
12699 
12700   std::string name = attributes.find( "name" )->second;
12701 
12702   // some types are not really types, but defines
12703   auto typeIt = m_types.find( name );
12704   if ( typeIt != m_types.end() )
12705   {
12706     assert( typeIt->second.referencedIn.empty() );
12707     assert( m_skippedTypes.find( name ) == m_skippedTypes.end() );
12708 
12709     switch ( typeIt->second.category )
12710     {
12711       case TypeCategory::Bitmask:
12712         assert( m_bitmasks.find( name ) != m_bitmasks.end() );
12713         m_bitmasks.erase( name );
12714         break;
12715       case TypeCategory::Enum:
12716         {
12717           auto enumIt = m_enums.find( name );
12718           assert( enumIt != m_enums.end() );
12719           assert( m_skippedEnums.find( name ) == m_skippedEnums.end() );
12720           m_skippedEnums[name] = enumIt->second;
12721           m_enums.erase( enumIt );
12722         }
12723         break;
12724       case TypeCategory::FuncPointer:
12725         assert( m_funcPointers.find( name ) != m_funcPointers.end() );
12726         m_funcPointers.erase( name );
12727         break;
12728       case TypeCategory::Handle:
12729         assert( m_handles.find( name ) != m_handles.end() );
12730         m_handles.erase( name );
12731         break;
12732       case TypeCategory::Struct:
12733         assert( m_structures.find( name ) != m_structures.end() );
12734         m_structures.erase( name );
12735         break;
12736       default: assert( false ); break;
12737     }
12738 
12739     m_skippedTypes[name] = typeIt->second;
12740     m_types.erase( typeIt );
12741   }
12742 }
12743 
readSPIRVCapabilities(tinyxml2::XMLElement const * element)12744 void VulkanHppGenerator::readSPIRVCapabilities( tinyxml2::XMLElement const * element )
12745 {
12746   int                                line       = element->GetLineNum();
12747   std::map<std::string, std::string> attributes = getAttributes( element );
12748   checkAttributes( line, attributes, { { "comment", {} } }, {} );
12749   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12750   checkElements( line, children, {}, { "spirvcapability" } );
12751 
12752   for ( auto child : children )
12753   {
12754     assert( child->Value() == std::string( "spirvcapability" ) );
12755     readSPIRVCapabilitiesSPIRVCapability( child );
12756   }
12757 }
12758 
readSPIRVCapabilitiesSPIRVCapability(tinyxml2::XMLElement const * element)12759 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapability( tinyxml2::XMLElement const * element )
12760 {
12761   int                                line       = element->GetLineNum();
12762   std::map<std::string, std::string> attributes = getAttributes( element );
12763   checkAttributes( line, attributes, { { "name", {} } }, {} );
12764   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12765   checkElements( line, children, {}, { "enable" } );
12766 
12767   for ( auto child : children )
12768   {
12769     assert( child->Value() == std::string( "enable" ) );
12770     readSPIRVCapabilitiesSPIRVCapabilityEnable( child );
12771   }
12772 }
12773 
readSPIRVCapabilitiesSPIRVCapabilityEnable(tinyxml2::XMLElement const * element)12774 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnable( tinyxml2::XMLElement const * element )
12775 {
12776   int                                line       = element->GetLineNum();
12777   std::map<std::string, std::string> attributes = getAttributes( element );
12778   checkElements( line, getChildElements( element ), {}, {} );
12779 
12780   if ( attributes.find( "extension" ) != attributes.end() )
12781   {
12782     readSPIRVCapabilitiesSPIRVCapabilityEnableExtension( line, attributes );
12783   }
12784   else if ( attributes.find( "property" ) != attributes.end() )
12785   {
12786     readSPIRVCapabilitiesSPIRVCapabilityEnableProperty( line, attributes );
12787   }
12788   else if ( attributes.find( "struct" ) != attributes.end() )
12789   {
12790     readSPIRVCapabilitiesSPIRVCapabilityEnableStruct( line, attributes );
12791   }
12792   else if ( attributes.find( "version" ) != attributes.end() )
12793   {
12794     readSPIRVCapabilitiesSPIRVCapabilityEnableVersion( line, attributes );
12795   }
12796   else
12797   {
12798     checkForError( false, line, "unknown set of attributes specified for SPIR-V capability" );
12799   }
12800 }
12801 
readSPIRVCapabilitiesSPIRVCapabilityEnableExtension(int xmlLine,std::map<std::string,std::string> const & attributes)12802 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableExtension( int xmlLine, std::map<std::string, std::string> const & attributes )
12803 {
12804   checkAttributes( xmlLine, attributes, { { "extension", {} } }, {} );
12805 
12806   checkForError( attributes.size() == 1, xmlLine, "unexpected attributes in addition to <extension> specified for SPIR-V capability" );
12807   for ( auto const & attribute : attributes )
12808   {
12809     assert( attribute.first == "extension" );
12810     checkForError(
12811       m_extensions.find( attribute.second ) != m_extensions.end(), xmlLine, "unknown extension <" + attribute.second + "> specified for SPIR-V capability" );
12812   }
12813 }
12814 
readSPIRVCapabilitiesSPIRVCapabilityEnableProperty(int xmlLine,std::map<std::string,std::string> const & attributes)12815 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableProperty( int xmlLine, std::map<std::string, std::string> const & attributes )
12816 {
12817   checkAttributes( xmlLine, attributes, { { "member", {} }, { "property", {} }, { "requires", {} }, { "value", {} } }, {} );
12818 
12819   std::string member, property, value;
12820   for ( auto const & attribute : attributes )
12821   {
12822     if ( attribute.first == "member" )
12823     {
12824       member = attribute.second;
12825     }
12826     else if ( attribute.first == "property" )
12827     {
12828       property = attribute.second;
12829     }
12830     if ( attribute.first == "requires" )
12831     {
12832       std::vector<std::string> requiresAttribute = tokenize( attribute.second, "," );
12833       for ( auto const & r : requiresAttribute )
12834       {
12835         checkForError( ( m_features.find( r ) != m_features.end() ) || ( m_extensions.find( r ) != m_extensions.end() ),
12836                        xmlLine,
12837                        "unknown requires <" + r + "> specified for SPIR-V capability" );
12838       }
12839     }
12840     else if ( attribute.first == "value" )
12841     {
12842       value = attribute.second;
12843     }
12844   }
12845   assert( !member.empty() && !property.empty() && !value.empty() );
12846 
12847   auto propertyIt = m_structures.find( property );
12848   checkForError( propertyIt != m_structures.end(), xmlLine, "unknown property <" + property + "> specified for SPIR-V capability" );
12849   auto memberIt = findStructMemberIt( member, propertyIt->second.members );
12850   checkForError( memberIt != propertyIt->second.members.end(), xmlLine, "unknown member <" + member + "> specified for SPIR-V capability" );
12851   if ( memberIt->type.type == "VkBool32" )
12852   {
12853     checkForError( ( value == "VK_FALSE" ) || ( value == "VK_TRUE" ),
12854                    xmlLine,
12855                    "unknown value <" + value + "> for boolean member <" + member + "> specified for SPIR-V capability" );
12856   }
12857   else
12858   {
12859     auto bitmaskIt = m_bitmasks.find( memberIt->type.type );
12860     checkForError( bitmaskIt != m_bitmasks.end(), xmlLine, "attribute member = <" + member + "> specified for SPIR-V capability is not a bitmask" );
12861     assert( !bitmaskIt->second.requirements.empty() );
12862     auto enumIt = m_enums.find( bitmaskIt->second.requirements );
12863     checkForError( enumIt != m_enums.end(),
12864                    xmlLine,
12865                    "attribute member = <" + member + "> specified for SPIR-V capability requires an unknown enum <" + bitmaskIt->second.requirements + ">" );
12866     auto valueIt =
12867       std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&value]( EnumValueData const & evd ) { return evd.name == value; } );
12868     checkForError( valueIt != enumIt->second.values.end(), xmlLine, "unknown attribute value = <" + value + "> specified for SPIR-V capability" );
12869   }
12870 }
12871 
readSPIRVCapabilitiesSPIRVCapabilityEnableStruct(int xmlLine,std::map<std::string,std::string> const & attributes)12872 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableStruct( int xmlLine, std::map<std::string, std::string> const & attributes )
12873 {
12874   checkAttributes( xmlLine, attributes, { { "feature", {} }, { "struct", {} } }, { { "alias", {} }, { "requires", {} } } );
12875 
12876   for ( auto const & attribute : attributes )
12877   {
12878     if ( attribute.first == "requires" )
12879     {
12880       std::vector<std::string> requiresAttribute = tokenize( attribute.second, "," );
12881       for ( auto const & r : requiresAttribute )
12882       {
12883         checkForError( ( m_features.find( r ) != m_features.end() ) || ( m_extensions.find( r ) != m_extensions.end() ),
12884                        xmlLine,
12885                        "unknown requires <" + r + "> specified for SPIR-V capability" );
12886       }
12887     }
12888     else if ( attribute.first == "struct" )
12889     {
12890       checkForError( ( m_structures.find( attribute.second ) != m_structures.end() ) ||
12891                        ( m_structureAliases.find( attribute.second ) != m_structureAliases.end() ),
12892                      xmlLine,
12893                      "unknown structure <" + attribute.second + "> specified for SPIR-V capability" );
12894       checkForError( attributes.find( "feature" ) != attributes.end(),
12895                      xmlLine,
12896                      "missing feature attribute for SPIR-V capability specified with struct <" + attribute.second + ">" );
12897     }
12898     else
12899     {
12900       assert( ( attribute.first == "alias" ) || ( attribute.first == "feature" ) );
12901     }
12902   }
12903 }
12904 
readSPIRVCapabilitiesSPIRVCapabilityEnableVersion(int xmlLine,std::map<std::string,std::string> const & attributes)12905 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableVersion( int xmlLine, std::map<std::string, std::string> const & attributes )
12906 {
12907   checkAttributes( xmlLine, attributes, { { "version", {} } }, {} );
12908 
12909   checkForError( attributes.size() == 1, xmlLine, "unexpected attributes in addition to <version> specified for SPIR-V capability" );
12910   for ( auto const & attribute : attributes )
12911   {
12912     assert( attribute.first == "version" );
12913     std::string feature = attribute.second;
12914     if ( feature.starts_with( "VK_API_" ) )
12915     {
12916       feature.erase( 3, 4 );  // remove "API_" from the version -> VK_VERSION_x_y
12917     }
12918     checkForError( feature.starts_with( "VK_VERSION_" ), xmlLine, "unknown version <" + attribute.second + "> specified for SPIR-V capability" );
12919     checkForError( m_features.find( feature ) != m_features.end(), xmlLine, "unknown version <" + attribute.second + "> specified for SPIR-V capability" );
12920   }
12921 }
12922 
readSPIRVExtensions(tinyxml2::XMLElement const * element)12923 void VulkanHppGenerator::readSPIRVExtensions( tinyxml2::XMLElement const * element )
12924 {
12925   int                                line       = element->GetLineNum();
12926   std::map<std::string, std::string> attributes = getAttributes( element );
12927   checkAttributes( line, attributes, { { "comment", {} } }, {} );
12928   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12929   checkElements( line, children, {}, { "spirvextension" } );
12930 
12931   for ( auto child : children )
12932   {
12933     assert( child->Value() == std::string( "spirvextension" ) );
12934     readSPIRVExtensionsExtension( child );
12935   }
12936 }
12937 
readSPIRVExtensionsExtension(tinyxml2::XMLElement const * element)12938 void VulkanHppGenerator::readSPIRVExtensionsExtension( tinyxml2::XMLElement const * element )
12939 {
12940   int                                line       = element->GetLineNum();
12941   std::map<std::string, std::string> attributes = getAttributes( element );
12942   checkAttributes( line, attributes, { { "name", {} } }, {} );
12943   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12944   checkElements( line, children, {}, { "enable" } );
12945 
12946   for ( auto child : children )
12947   {
12948     assert( child->Value() == std::string( "enable" ) );
12949     readSPIRVExtensionsExtensionEnable( child );
12950   }
12951 }
12952 
readSPIRVExtensionsExtensionEnable(tinyxml2::XMLElement const * element)12953 void VulkanHppGenerator::readSPIRVExtensionsExtensionEnable( tinyxml2::XMLElement const * element )
12954 {
12955   int                                line       = element->GetLineNum();
12956   std::map<std::string, std::string> attributes = getAttributes( element );
12957   checkAttributes( line, attributes, {}, { { "extension", {} }, { "version", {} } } );
12958   checkElements( line, getChildElements( element ), {}, {} );
12959 
12960   checkForError( !attributes.empty(), line, "no version or extension specified for SPIR-V extension" );
12961   for ( auto const & attribute : attributes )
12962   {
12963     if ( attribute.first == "extension" )
12964     {
12965       checkForError(
12966         m_extensions.find( attribute.second ) != m_extensions.end(), line, "unknown extension <" + attribute.second + "> specified for SPIR-V extension" );
12967     }
12968     else
12969     {
12970       assert( attribute.first == "version" );
12971       std::string feature = attribute.second;
12972       if ( feature.starts_with( "VK_API_" ) )
12973       {
12974         feature.erase( 3, 4 );  // remove "API_" from the version -> VK_VERSION_x_y
12975       }
12976       checkForError( feature.starts_with( "VK_VERSION_" ), line, "unknown version <" + attribute.second + "> specified for SPIR-V extension" );
12977       checkForError( m_features.find( feature ) != m_features.end(), line, "unknown version <" + attribute.second + "> specified for SPIR-V extension" );
12978     }
12979   }
12980 }
12981 
readTags(tinyxml2::XMLElement const * element)12982 void VulkanHppGenerator::readTags( tinyxml2::XMLElement const * element )
12983 {
12984   int line = element->GetLineNum();
12985   checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
12986   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12987   checkElements( line, children, { { "tag", false } } );
12988 
12989   for ( auto child : children )
12990   {
12991     readTagsTag( child );
12992   }
12993 }
12994 
readTagsTag(tinyxml2::XMLElement const * element)12995 void VulkanHppGenerator::readTagsTag( tinyxml2::XMLElement const * element )
12996 {
12997   int                                line       = element->GetLineNum();
12998   std::map<std::string, std::string> attributes = getAttributes( element );
12999   checkAttributes( line, attributes, { { "author", {} }, { "contact", {} }, { "name", {} } }, {} );
13000   checkElements( line, getChildElements( element ), {} );
13001 
13002   for ( auto const & attribute : attributes )
13003   {
13004     if ( attribute.first == "name" )
13005     {
13006       checkForError( m_tags.find( attribute.second ) == m_tags.end(), line, "tag named <" + attribute.second + "> has already been specified" );
13007       m_tags.insert( attribute.second );
13008     }
13009     else
13010     {
13011       checkForError( ( attribute.first == "author" ) || ( attribute.first == "contact" ), line, "unknown attribute <" + attribute.first + ">" );
13012     }
13013   }
13014 }
13015 
readTypes(tinyxml2::XMLElement const * element)13016 void VulkanHppGenerator::readTypes( tinyxml2::XMLElement const * element )
13017 {
13018   int line = element->GetLineNum();
13019   checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
13020   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13021   checkElements( line, children, { { "comment", false }, { "type", false } } );
13022 
13023   for ( auto child : children )
13024   {
13025     std::string value = child->Value();
13026     if ( value == "comment" )
13027     {
13028       readComment( child );
13029     }
13030     else
13031     {
13032       assert( value == "type" );
13033       readTypesType( child );
13034     }
13035   }
13036 }
13037 
readTypesType(tinyxml2::XMLElement const * element)13038 void VulkanHppGenerator::readTypesType( tinyxml2::XMLElement const * element )
13039 {
13040   int                                line       = element->GetLineNum();
13041   std::map<std::string, std::string> attributes = getAttributes( element );
13042 
13043   auto categoryIt = attributes.find( "category" );
13044   if ( categoryIt != attributes.end() )
13045   {
13046     if ( categoryIt->second == "basetype" )
13047     {
13048       readTypesTypeBasetype( element, attributes );
13049     }
13050     else if ( categoryIt->second == "bitmask" )
13051     {
13052       readTypesTypeBitmask( element, attributes );
13053     }
13054     else if ( categoryIt->second == "define" )
13055     {
13056       readTypesTypeDefine( element, attributes );
13057     }
13058     else if ( categoryIt->second == "enum" )
13059     {
13060       readTypesTypeEnum( element, attributes );
13061     }
13062     else if ( categoryIt->second == "funcpointer" )
13063     {
13064       readTypesTypeFuncpointer( element, attributes );
13065     }
13066     else if ( categoryIt->second == "handle" )
13067     {
13068       readTypesTypeHandle( element, attributes );
13069     }
13070     else if ( categoryIt->second == "include" )
13071     {
13072       readTypesTypeInclude( element, attributes );
13073     }
13074     else if ( categoryIt->second == "struct" )
13075     {
13076       readTypesTypeStruct( element, false, attributes );
13077     }
13078     else
13079     {
13080       checkForError( categoryIt->second == "union", element->GetLineNum(), "unknown type category <" + categoryIt->second + ">" );
13081       readTypesTypeStruct( element, true, attributes );
13082     }
13083   }
13084   else
13085   {
13086     auto requiresIt = attributes.find( "requires" );
13087     if ( requiresIt != attributes.end() )
13088     {
13089       readTypesTypeRequires( element, attributes );
13090     }
13091     else
13092     {
13093       checkForError( ( attributes.size() == 1 ) && ( attributes.begin()->first == "name" ) && ( attributes.begin()->second == "int" ), line, "unknown type" );
13094       checkForError( m_types.insert( std::make_pair( attributes.begin()->second, TypeData{ .category = TypeCategory::Unknown } ) ).second,
13095                      line,
13096                      "type <" + attributes.begin()->second + "> already specified" );
13097     }
13098   }
13099 }
13100 
readTypesTypeBasetype(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13101 void VulkanHppGenerator::readTypesTypeBasetype( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13102 {
13103   int line = element->GetLineNum();
13104   checkAttributes( line, attributes, { { "category", { "basetype" } } }, {} );
13105 
13106   NameData nameData;
13107   TypeInfo typeInfo;
13108   std::tie( nameData, typeInfo ) = readNameAndType( element );
13109 
13110   if ( typeInfo.prefix == "typedef" )
13111   {
13112     // remove redundant typeInfo.prefix "typedef"
13113     typeInfo.prefix.clear();
13114   }
13115 
13116   checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
13117   checkForError( typeInfo.prefix.empty(), line, "unexpected type prefix <" + typeInfo.prefix + ">" );
13118   checkForError( typeInfo.postfix.empty() || ( typeInfo.postfix == "*" ), line, "unexpected type postfix <" + typeInfo.postfix + ">" );
13119 
13120   if ( !typeInfo.type.empty() )
13121   {
13122     checkForError( m_baseTypes.insert( std::make_pair( nameData.name, BaseTypeData( typeInfo, line ) ) ).second,
13123                    line,
13124                    "basetype <" + nameData.name + "> already specified" );
13125   }
13126   checkForError( m_types.insert( std::make_pair( nameData.name, TypeData{ .category = TypeCategory::BaseType } ) ).second,
13127                  line,
13128                  "basetype <" + nameData.name + "> already specified as a type" );
13129 }
13130 
readTypesTypeBitmask(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13131 void VulkanHppGenerator::readTypesTypeBitmask( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13132 {
13133   int line = element->GetLineNum();
13134 
13135   auto aliasIt = attributes.find( "alias" );
13136   if ( aliasIt != attributes.end() )
13137   {
13138     checkAttributes( line, attributes, { { "alias", {} }, { "category", { "bitmask" } }, { "name", {} } }, {} );
13139     checkElements( line, getChildElements( element ), {} );
13140 
13141     std::string alias, name;
13142     for ( auto const & attribute : attributes )
13143     {
13144       if ( attribute.first == "alias" )
13145       {
13146         alias = attribute.second;
13147       }
13148       else if ( attribute.first == "name" )
13149       {
13150         name = attribute.second;
13151       }
13152     }
13153 
13154     auto bitmasksIt = m_bitmasks.find( alias );
13155     checkForError( bitmasksIt != m_bitmasks.end(), line, "missing alias <" + alias + ">." );
13156     checkForError(
13157       bitmasksIt->second.alias.empty(), line, "alias for bitmask <" + bitmasksIt->first + "> already specified as <" + bitmasksIt->second.alias + ">" );
13158     bitmasksIt->second.alias = name;
13159     checkForError( m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Bitmask } ) ).second,
13160                    line,
13161                    "aliased bitmask <" + name + "> already specified as a type" );
13162   }
13163   else
13164   {
13165     checkAttributes( line, attributes, { { "category", { "bitmask" } } }, { { "api", { "vulkan", "vulkansc" } }, { "bitvalues", {} }, { "requires", {} } } );
13166 
13167     std::string bitvalues, requirements;
13168     for ( auto const & attribute : attributes )
13169     {
13170       if ( attribute.first == "api" )
13171       {
13172         if ( attribute.second == "vulkansc" )
13173         {
13174           return;  // skip stuff marked as "vulkansc" !
13175         }
13176         assert( attribute.second == "vulkan" );
13177       }
13178       else if ( attribute.first == "bitvalues" )
13179       {
13180         bitvalues = attribute.second;
13181       }
13182       else if ( attribute.first == "requires" )
13183       {
13184         requirements = attribute.second;
13185       }
13186     }
13187 
13188     NameData nameData;
13189     TypeInfo typeInfo;
13190     std::tie( nameData, typeInfo ) = readNameAndType( element );
13191 
13192     checkForError( nameData.name.starts_with( "Vk" ), line, "name <" + nameData.name + "> does not begin with <Vk>" );
13193     checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
13194     checkForWarning( ( typeInfo.type == "VkFlags" ) || ( typeInfo.type == "VkFlags64" ), line, "unexpected bitmask type <" + typeInfo.type + ">" );
13195     checkForError( typeInfo.prefix == "typedef", line, "unexpected type prefix <" + typeInfo.prefix + ">" );
13196     checkForError( typeInfo.postfix.empty(), line, "unexpected type postfix <" + typeInfo.postfix + ">" );
13197     checkForError( bitvalues.empty() || requirements.empty(), line, "attributes <bitvalues> and <requires> are both specified" );
13198     checkForError( ( typeInfo.type != "VkFlags64" ) || !bitvalues.empty(), line, "bitmask of type <VkFlags64> needs attribute bitvalues to be set" );
13199 
13200     if ( !bitvalues.empty() )
13201     {
13202       requirements = bitvalues;
13203     }
13204     m_bitmasks.insert( std::make_pair( nameData.name, BitmaskData( requirements, typeInfo.type, line ) ) );
13205     checkForError( m_types.insert( std::make_pair( nameData.name, TypeData{ .category = TypeCategory::Bitmask } ) ).second,
13206                    line,
13207                    "bitmask <" + nameData.name + "> already specified as a type" );
13208   }
13209 }
13210 
readTypesTypeDefine(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13211 void VulkanHppGenerator::readTypesTypeDefine( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13212 {
13213   int line = element->GetLineNum();
13214   checkAttributes( line, attributes, { { "category", { "define" } } }, { { "api", { "vulkan", "vulkansc" } }, { "name", {} }, { "requires", {} } } );
13215 
13216   std::string name, require;
13217   for ( auto const & attribute : attributes )
13218   {
13219     if ( attribute.first == "api" )
13220     {
13221       if ( attribute.second == "vulkansc" )
13222       {
13223         return;  // skip stuff marked as "vulkansc" !
13224       }
13225       assert( attribute.second == "vulkan" );
13226     }
13227     else if ( attribute.first == "name" )
13228     {
13229       name = attribute.second;
13230     }
13231     else if ( attribute.first == "requires" )
13232     {
13233       require = attribute.second;
13234     }
13235   }
13236 
13237   if ( !name.empty() )
13238   {
13239     checkForError( !element->FirstChildElement(), line, "unknown formatting of type category=define name <" + name + ">" );
13240     checkForError( element->LastChild() && element->LastChild()->ToText() && element->LastChild()->ToText()->Value(),
13241                    line,
13242                    "unknown formatting of type category=define named <" + name + ">" );
13243 
13244     // filter out the check for the different types of VK_DEFINE_NON_DISPATCHABLE_HANDLE
13245     if ( name == "VK_USE_64_BIT_PTR_DEFINES" )
13246     {
13247       m_typesafeCheck = "#if ( VK_USE_64_BIT_PTR_DEFINES == 1 )";
13248     }
13249     else if ( ( name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE" ) && ( m_typesafeCheck.empty() ) )
13250     {
13251       std::string text  = element->LastChild()->ToText()->Value();
13252       size_t      start = text.find( "#if defined(__LP64__)" );
13253       checkForError( start != std::string::npos, line, "unexpected text in type category=define named <" + name + ">" );
13254       size_t end = text.find_first_of( "\r\n", start + 1 );
13255       checkForError( end != std::string::npos, line, "unexpected text in type category=define named <" + name + ">" );
13256       m_typesafeCheck = text.substr( start, end - start );
13257     }
13258   }
13259   else if ( element->GetText() )
13260   {
13261     std::string text = element->GetText();
13262     if ( ( text.find( "class" ) != std::string::npos ) || ( text.find( "struct" ) != std::string::npos ) )
13263     {
13264       // here are a couple of structs as defines, which really are types!
13265       tinyxml2::XMLElement const * child = element->FirstChildElement();
13266       checkForError( child && ( strcmp( child->Value(), "name" ) == 0 ) && child->GetText(), line, "unexpected formatting of type category=define" );
13267       name = child->GetText();
13268       checkForError(
13269         m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Define } ) ).second, line, "type <" + name + "> has already been speficied" );
13270     }
13271     else
13272     {
13273       tinyxml2::XMLElement const * child = element->FirstChildElement();
13274       checkForError( child && !child->FirstAttribute() && ( strcmp( child->Value(), "name" ) == 0 ) && child->GetText(),
13275                      line,
13276                      "unknown formatting of type category define" );
13277       name = trim( child->GetText() );
13278       if ( name == "VK_HEADER_VERSION" )
13279       {
13280         m_version = trimEnd( element->LastChild()->ToText()->Value() );
13281       }
13282       // ignore all the other defines
13283       checkForWarning( !child->NextSiblingElement() ||
13284                          ( child->NextSiblingElement() && !child->NextSiblingElement()->FirstAttribute() &&
13285                            ( strcmp( child->NextSiblingElement()->Value(), "type" ) == 0 ) && !child->NextSiblingElement()->NextSiblingElement() ),
13286                        line,
13287                        "unknown formatting of type category define" );
13288     }
13289   }
13290 
13291   assert( !name.empty() );
13292   checkForError( m_defines.insert( { name, { require, line } } ).second, line, "define <" + name + "> has already been specified" );
13293 }
13294 
readTypesTypeEnum(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13295 void VulkanHppGenerator::readTypesTypeEnum( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13296 {
13297   int line = element->GetLineNum();
13298   checkAttributes( line, attributes, { { "category", { "enum" } }, { "name", {} } }, { { "alias", {} } } );
13299   checkElements( line, getChildElements( element ), {} );
13300 
13301   std::string alias, name;
13302   for ( auto const & attribute : attributes )
13303   {
13304     if ( attribute.first == "alias" )
13305     {
13306       alias = attribute.second;
13307       checkForError( !alias.empty(), line, "enum with empty alias" );
13308     }
13309     else if ( attribute.first == "name" )
13310     {
13311       name = attribute.second;
13312       checkForError( !name.empty(), line, "enum with empty name" );
13313       checkForError( m_enums.find( name ) == m_enums.end(), line, "enum <" + name + "> already specified" );
13314     }
13315   }
13316   assert( !name.empty() );
13317 
13318   if ( alias.empty() )
13319   {
13320     checkForError( m_enums.insert( std::make_pair( name, EnumData{ .xmlLine = line } ) ).second, line, "enum <" + name + "> already specified" );
13321   }
13322   else
13323   {
13324     auto enumIt = m_enums.find( alias );
13325     checkForError( enumIt != m_enums.end(), line, "enum with unknown alias <" + alias + ">" );
13326     checkForError( enumIt->second.alias.empty(), line, "enum <" + enumIt->first + "> already has an alias <" + enumIt->second.alias + ">" );
13327     enumIt->second.alias = name;
13328   }
13329   checkForError(
13330     m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Enum } ) ).second, line, "enum <" + name + "> already specified as a type" );
13331 }
13332 
readTypesTypeFuncpointer(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13333 void VulkanHppGenerator::readTypesTypeFuncpointer( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13334 {
13335   int line = element->GetLineNum();
13336   checkAttributes( line, attributes, { { "category", { "funcpointer" } } }, { { "requires", {} } } );
13337   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13338   checkElements( line, children, { { "name", true } }, { "type" } );
13339 
13340   std::string requirements;
13341   for ( auto const & attribute : attributes )
13342   {
13343     if ( attribute.first == "requires" )
13344     {
13345       requirements = attribute.second;
13346     }
13347   }
13348 
13349   auto                  funcPointerIt = m_funcPointers.end();
13350   std::set<std::string> argumentNames;
13351   for ( auto const & child : children )
13352   {
13353     std::string value     = child->Value();
13354     int         childLine = child->GetLineNum();
13355     if ( value == "name" )
13356     {
13357       std::string name = child->GetText();
13358       checkForError( !name.empty(), childLine, "funcpointer with empty name" );
13359       checkForError( m_funcPointers.find( name ) == m_funcPointers.end(), childLine, "funcpointer <" + name + "> already specified" );
13360       funcPointerIt = m_funcPointers.insert( std::make_pair( name, FuncPointerData( requirements, line ) ) ).first;
13361       checkForError( m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::FuncPointer } ) ).second,
13362                      childLine,
13363                      "funcpointer <" + name + "> already specified as a type" );
13364     }
13365     else if ( value == "type" )
13366     {
13367       assert( funcPointerIt != m_funcPointers.end() );
13368       std::string type = child->GetText();
13369       funcPointerIt->second.arguments.push_back( { type, childLine } );
13370 
13371       auto         sibling      = child->NextSibling();
13372       char const * siblingValue = sibling->Value();
13373       assert( siblingValue != nullptr );
13374       std::string argumentName = siblingValue;
13375       argumentName             = argumentName.substr( argumentName.find_first_not_of( "* " ) );
13376       argumentName             = argumentName.substr( 0, argumentName.find_first_of( ",)" ) );
13377       checkForError( argumentNames.insert( argumentName ).second,
13378                      childLine,
13379                      "funcpointer <" + funcPointerIt->first + "> already has an argument named <" + argumentName + ">" );
13380     }
13381   }
13382 }
13383 
readTypesTypeHandle(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13384 void VulkanHppGenerator::readTypesTypeHandle( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13385 {
13386   int line = element->GetLineNum();
13387 
13388   auto aliasIt = attributes.find( "alias" );
13389   if ( aliasIt != attributes.end() )
13390   {
13391     checkAttributes( line, attributes, { { "alias", {} }, { "category", { "handle" } }, { "name", {} } }, {} );
13392     checkElements( line, getChildElements( element ), {} );
13393 
13394     auto handlesIt = m_handles.find( aliasIt->second );
13395     checkForError( handlesIt != m_handles.end(), line, "using unspecified alias <" + aliasIt->second + ">." );
13396     checkForError( handlesIt->second.alias.empty(), line, "handle <" + handlesIt->first + "> already has an alias <" + handlesIt->second.alias + ">" );
13397     handlesIt->second.alias = attributes.find( "name" )->second;
13398     checkForError( m_types.insert( std::make_pair( handlesIt->second.alias, TypeData{ .category = TypeCategory::Handle } ) ).second,
13399                    line,
13400                    "handle alias <" + handlesIt->second.alias + "> already specified as a type" );
13401   }
13402   else
13403   {
13404     checkAttributes( line, attributes, { { "category", { "handle" } } }, { { "objtypeenum", {} }, { "parent", {} } } );
13405 
13406     std::string objTypeEnum, parent;
13407     for ( auto const & attribute : attributes )
13408     {
13409       if ( attribute.first == "objtypeenum" )
13410       {
13411         objTypeEnum = attribute.second;
13412       }
13413       else if ( attribute.first == "parent" )
13414       {
13415         parent = attribute.second;
13416       }
13417     }
13418 
13419     NameData nameData;
13420     TypeInfo typeInfo;
13421     std::tie( nameData, typeInfo ) = readNameAndType( element );
13422     const bool isDispatchable      = typeInfo.type == "VK_DEFINE_HANDLE";
13423 
13424     checkForError( nameData.name.starts_with( "Vk" ), line, "name <" + nameData.name + "> does not begin with <Vk>" );
13425     checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
13426     checkForError( ( typeInfo.type == "VK_DEFINE_HANDLE" ) || ( typeInfo.type == "VK_DEFINE_NON_DISPATCHABLE_HANDLE" ),
13427                    line,
13428                    "handle with invalid type <" + typeInfo.type + ">" );
13429     checkForError( typeInfo.prefix.empty(), line, "unexpected type prefix <" + typeInfo.prefix + ">" );
13430     checkForError( typeInfo.postfix == "(", line, "unexpected type postfix <" + typeInfo.postfix + ">" );
13431     checkForError( !objTypeEnum.empty(), line, "handle <" + nameData.name + "> does not specify attribute \"objtypeenum\"" );
13432 
13433     checkForError( parent.find( ',' ) == std::string::npos, line, "mulitple parents specified for handle <" + nameData.name + ">" );
13434     checkForError( m_handles.insert( std::make_pair( nameData.name, HandleData( parent, objTypeEnum, isDispatchable, line ) ) ).second,
13435                    line,
13436                    "handle <" + nameData.name + "> already specified" );
13437     checkForError( m_types.insert( std::make_pair( nameData.name, TypeData{ .category = TypeCategory::Handle } ) ).second,
13438                    line,
13439                    "handle <" + nameData.name + "> already specified as a type" );
13440   }
13441 }
13442 
readTypesTypeInclude(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13443 void VulkanHppGenerator::readTypesTypeInclude( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13444 {
13445   int line = element->GetLineNum();
13446   checkAttributes( line, attributes, { { "category", { "include" } }, { "name", {} } }, {} );
13447   checkElements( line, getChildElements( element ), {} );
13448 
13449   std::string name = attributes.find( "name" )->second;
13450   checkForError( m_includes.insert( name ).second, element->GetLineNum(), "include named <" + name + "> already specified" );
13451 }
13452 
readTypesTypeRequires(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13453 void VulkanHppGenerator::readTypesTypeRequires( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13454 {
13455   int line = element->GetLineNum();
13456   checkAttributes( line, attributes, { { "name", {} }, { "requires", {} } }, {} );
13457   checkElements( line, getChildElements( element ), {} );
13458 
13459   for ( auto attribute : attributes )
13460   {
13461     if ( attribute.first == "name" )
13462     {
13463       checkForError( m_types.insert( std::make_pair( attribute.second, TypeData{ .category = TypeCategory::Requires } ) ).second,
13464                      line,
13465                      "type named <" + attribute.second + "> already specified" );
13466     }
13467     else
13468     {
13469       assert( attribute.first == "requires" );
13470       checkForError( m_includes.find( attribute.second ) != m_includes.end(), line, "type requires unknown include <" + attribute.second + ">" );
13471     }
13472   }
13473 }
13474 
readTypesTypeStruct(tinyxml2::XMLElement const * element,bool isUnion,std::map<std::string,std::string> const & attributes)13475 void VulkanHppGenerator::readTypesTypeStruct( tinyxml2::XMLElement const * element, bool isUnion, std::map<std::string, std::string> const & attributes )
13476 {
13477   int line = element->GetLineNum();
13478   if ( attributes.find( "alias" ) != attributes.end() )
13479   {
13480     checkAttributes( line, attributes, { { "alias", {} }, { "category", { "struct" } }, { "name", {} } }, {} );
13481     checkElements( line, getChildElements( element ), {}, {} );
13482 
13483     std::string alias, name;
13484     for ( auto const & attribute : attributes )
13485     {
13486       if ( attribute.first == "alias" )
13487       {
13488         alias = attribute.second;
13489       }
13490       else if ( attribute.first == "name" )
13491       {
13492         name = attribute.second;
13493       }
13494     }
13495 
13496     checkForError(
13497       m_structureAliases.insert( std::make_pair( name, StructureAliasData( alias, line ) ) ).second, line, "structure alias <" + name + "> already used" );
13498     checkForError( m_structureAliasesInverse[alias].insert( name ).second, line, "structure alias <" + name + "> already used with structure <" + alias + ">" );
13499     checkForError( m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Struct } ) ).second,
13500                    line,
13501                    "struct <" + name + "> already specified as a type" );
13502   }
13503   else
13504   {
13505     checkAttributes( line,
13506                      attributes,
13507                      { { "category", { isUnion ? "union" : "struct" } }, { "name", {} } },
13508                      { { "allowduplicate", { "false", "true" } }, { "comment", {} }, { "returnedonly", { "true" } }, { "structextends", {} } } );
13509     std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13510     checkElements( line, children, {}, { "member", "comment" } );
13511 
13512     std::string              category, name;
13513     std::vector<std::string> structExtends;
13514     bool                     allowDuplicate = false;
13515     bool                     returnedOnly   = false;
13516     for ( auto const & attribute : attributes )
13517     {
13518       if ( attribute.first == "allowduplicate" )
13519       {
13520         allowDuplicate = ( attribute.second == "true" );
13521       }
13522       else if ( attribute.first == "category" )
13523       {
13524         category = attribute.second;
13525       }
13526       else if ( attribute.first == "name" )
13527       {
13528         name = attribute.second;
13529       }
13530       else if ( attribute.first == "returnedonly" )
13531       {
13532         checkForError( attribute.second == "true", line, "unknown value for attribute returnedonly: <" + attribute.second + ">" );
13533         returnedOnly = true;
13534       }
13535       else if ( attribute.first == "structextends" )
13536       {
13537         structExtends = tokenize( attribute.second, "," );
13538       }
13539     }
13540     assert( !name.empty() );
13541     // make this warn a check, as soon as vk.xml has been fixed on attribute "allowduplicate" !
13542     checkForWarning( !allowDuplicate || !structExtends.empty(), line, "attribute <allowduplicate> is true, but no structures are listed in <structextends>" );
13543 
13544     checkForError( m_structures.find( name ) == m_structures.end(), line, "struct <" + name + "> already specfied" );
13545     std::map<std::string, StructureData>::iterator it = m_structures.insert( std::make_pair( name, StructureData( structExtends, line ) ) ).first;
13546     it->second.allowDuplicate                         = allowDuplicate;
13547     it->second.isUnion                                = isUnion;
13548     it->second.returnedOnly                           = returnedOnly;
13549 
13550     for ( auto child : children )
13551     {
13552       std::string value = child->Value();
13553       if ( value == "comment" )
13554       {
13555         readComment( child );
13556       }
13557       else if ( value == "member" )
13558       {
13559         readTypesTypeStructMember( child, it->second.members, isUnion );
13560       }
13561     }
13562     it->second.subStruct = determineSubStruct( *it );
13563 
13564     // check if multiple structure members use the very same (not empty) len attribute
13565     // Note: even though the arrays are not marked as optional, they still might be mutually exclusive (like in
13566     // VkWriteDescriptorSet)! That is, there's not enough information available in vk.xml to decide on that, so we
13567     // need this external knowledge!
13568     static std::set<std::string> mutualExclusiveStructs = {
13569       "VkAccelerationStructureBuildGeometryInfoKHR", "VkAccelerationStructureTrianglesOpacityMicromapEXT", "VkMicromapBuildInfoEXT", "VkWriteDescriptorSet"
13570     };
13571     static std::set<std::string> multipleLenStructs = { "VkImageConstraintsInfoFUCHSIA",
13572                                                         "VkIndirectCommandsLayoutTokenNV",
13573                                                         "VkPresentInfoKHR",
13574                                                         "VkSemaphoreWaitInfo",
13575                                                         "VkSubmitInfo",
13576                                                         "VkSubpassDescription",
13577                                                         "VkSubpassDescription2",
13578                                                         "VkWin32KeyedMutexAcquireReleaseInfoKHR",
13579                                                         "VkWin32KeyedMutexAcquireReleaseInfoNV" };
13580     bool                         warned             = false;
13581     for ( auto m0It = it->second.members.begin(); !warned && ( m0It != it->second.members.end() ); ++m0It )
13582     {
13583       if ( !m0It->len.empty() && ( m0It->len.front() != "null-terminated" ) )
13584       {
13585         for ( auto m1It = std::next( m0It ); !warned && ( m1It != it->second.members.end() ); ++m1It )
13586         {
13587           if ( !m1It->len.empty() && ( m0It->len.front() == m1It->len.front() ) )
13588           {
13589             if ( mutualExclusiveStructs.find( it->first ) != mutualExclusiveStructs.end() )
13590             {
13591               it->second.mutualExclusiveLens = true;
13592             }
13593             else
13594             {
13595               checkForWarning(
13596                 multipleLenStructs.find( it->first ) != multipleLenStructs.end(),
13597                 line,
13598                 "Encountered structure <" + it->first +
13599                   "> with multiple members referencing the same member for len. Need to be checked if they are supposed to be mutually exclusive." );
13600               warned = true;
13601             }
13602           }
13603         }
13604       }
13605     }
13606 
13607     m_extendedStructs.insert( structExtends.begin(), structExtends.end() );
13608     checkForError(
13609       m_types.insert( std::make_pair( name, TypeData{ .category = ( category == "struct" ) ? TypeCategory::Struct : TypeCategory::Union } ) ).second,
13610       line,
13611       "struct <" + name + "> already specified as a type" );  // log type and alias in m_types
13612   }
13613 }
13614 
readTypesTypeStructMember(tinyxml2::XMLElement const * element,std::vector<MemberData> & members,bool isUnion)13615 void VulkanHppGenerator::readTypesTypeStructMember( tinyxml2::XMLElement const * element, std::vector<MemberData> & members, bool isUnion )
13616 {
13617   int                                line       = element->GetLineNum();
13618   std::map<std::string, std::string> attributes = getAttributes( element );
13619   checkAttributes( line,
13620                    attributes,
13621                    {},
13622                    { { "altlen", {} },
13623                      { "api", { "vulkan", "vulkansc" } },
13624                      { "externsync", { "true" } },
13625                      { "len", {} },
13626                      { "limittype", { "bitmask", "bits", "exact", "max", "min", "mul", "noauto", "pot", "range", "struct" } },
13627                      { "noautovalidity", { "true" } },
13628                      { "objecttype", { "objectType" } },
13629                      { "optional", { "false", "true" } },
13630                      { "selection", {} },
13631                      { "selector", {} },
13632                      { "values", {} } } );
13633   std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13634   checkElements( line, children, { { "name", true }, { "type", true } }, { "comment", "enum" } );
13635 
13636   MemberData memberData( line );
13637 
13638   for ( auto const & attribute : attributes )
13639   {
13640     if ( attribute.first == "api" )
13641     {
13642       if ( attribute.second == "vulkansc" )
13643       {
13644         return;  // skip stuff marked as "vulkansc" !
13645       }
13646       assert( attribute.second == "vulkan" );
13647     }
13648     else if ( attribute.first == "altlen" )
13649     {
13650       assert( memberData.len.empty() );
13651       memberData.len = tokenize( attribute.second, "," );
13652       checkForError( memberData.len.size() == 1, line, "member attribute <altlen> holds unknown number of data: " + std::to_string( memberData.len.size() ) );
13653       checkForError( altLens.find( memberData.len[0] ) != altLens.end(), line, "member attribute <altlen> holds unknown value <" + memberData.len[0] + ">" );
13654     }
13655     else if ( attribute.first == "len" )
13656     {
13657       if ( memberData.len.empty() )
13658       {
13659         memberData.len = tokenize( attribute.second, "," );
13660         checkForError( !memberData.len.empty() && ( memberData.len.size() <= 2 ),
13661                        line,
13662                        "member attribute <len> holds unknown number of data: " + std::to_string( memberData.len.size() ) );
13663         auto lenMember = findStructMemberIt( memberData.len[0], members );
13664         checkForError( lenMember != members.end() || ( memberData.len[0] == "null-terminated" ),
13665                        line,
13666                        "member attribute <len> holds unknown value <" + memberData.len[0] + ">" );
13667         if ( lenMember != members.end() )
13668         {
13669           checkForError( lenMember->type.prefix.empty(),
13670                          line,
13671                          "member attribute <len> references a member of unexpected type <" + lenMember->type.compose( "VULKAN_HPP_NAMESPACE" ) + ">" );
13672         }
13673         if ( 1 < memberData.len.size() )
13674         {
13675           checkForError( ( memberData.len[1] == "1" ) || ( memberData.len[1] == "null-terminated" ),
13676                          line,
13677                          "member attribute <len> holds unknown second value <" + memberData.len[1] + ">" );
13678         }
13679       }
13680     }
13681     else if ( attribute.first == "noautovalidity" )
13682     {
13683       memberData.noAutoValidity = ( attribute.second == "true" );
13684     }
13685     else if ( attribute.first == "optional" )
13686     {
13687       std::vector<std::string> optional = tokenize( attribute.second, "," );
13688       memberData.optional.reserve( optional.size() );
13689       for ( auto const & o : optional )
13690       {
13691         memberData.optional.push_back( o == "true" );
13692       }
13693     }
13694     else if ( attribute.first == "selection" )
13695     {
13696       checkForError( isUnion, line, "attribute <selection> is used with a non-union structure." );
13697       memberData.selection = tokenize( attribute.second, "," );
13698     }
13699     else if ( attribute.first == "selector" )
13700     {
13701       memberData.selector = attribute.second;
13702       auto selectorIt     = findStructMemberIt( memberData.selector, members );
13703       checkForError( selectorIt != members.end(), line, "member attribute <selector> holds unknown value <" + memberData.selector + ">" );
13704       checkForError( m_enums.find( selectorIt->type.type ) != m_enums.end(),
13705                      line,
13706                      "member attribute <selector> references unknown enum type <" + selectorIt->type.type + ">" );
13707     }
13708     else if ( attribute.first == "values" )
13709     {
13710       std::vector<std::string> values = tokenize( attribute.second, "," );
13711       checkForError( values.size() == 1, line, "attribute \"values\" holds multiple values <" + attribute.first + ">, but it's expected to hold just one" );
13712       memberData.value = values[0];
13713     }
13714   }
13715 
13716   for ( auto child : children )
13717   {
13718     std::string value = child->Value();
13719     if ( value == "enum" )
13720     {
13721       readTypesTypeStructMemberEnum( child, memberData );
13722     }
13723     else if ( value == "name" )
13724     {
13725       readTypesTypeStructMemberName( child, memberData, members );
13726     }
13727     else if ( value == "type" )
13728     {
13729       readTypesTypeStructMemberType( child, memberData );
13730     }
13731   }
13732 
13733   members.push_back( memberData );
13734 }
13735 
readTypesTypeStructMemberEnum(tinyxml2::XMLElement const * element,MemberData & memberData)13736 void VulkanHppGenerator::readTypesTypeStructMemberEnum( tinyxml2::XMLElement const * element, MemberData & memberData )
13737 {
13738   int line = element->GetLineNum();
13739   checkAttributes( line, getAttributes( element ), {}, {} );
13740   checkElements( line, getChildElements( element ), {}, {} );
13741 
13742   std::string enumString = element->GetText();
13743 
13744   checkForError( element->PreviousSibling() && ( strcmp( element->PreviousSibling()->Value(), "[" ) == 0 ) && element->NextSibling() &&
13745                    ( strcmp( element->NextSibling()->Value(), "]" ) == 0 ),
13746                  line,
13747                  std::string( "structure member array specifiation is ill-formatted: <" ) + enumString + ">" );
13748 
13749   memberData.arraySizes.push_back( enumString );
13750   checkForError( memberData.usedConstant.empty(), line, "struct already holds a constant <" + memberData.usedConstant + ">" );
13751   memberData.usedConstant = enumString;
13752 }
13753 
readTypesTypeStructMemberName(tinyxml2::XMLElement const * element,MemberData & memberData,std::vector<MemberData> const & members)13754 void VulkanHppGenerator::readTypesTypeStructMemberName( tinyxml2::XMLElement const * element, MemberData & memberData, std::vector<MemberData> const & members )
13755 {
13756   int line = element->GetLineNum();
13757   checkAttributes( line, getAttributes( element ), {}, {} );
13758   checkElements( line, getChildElements( element ), {}, {} );
13759 
13760   std::string name = element->GetText();
13761   checkForError( !isStructMember( name, members ), line, "structure member name <" + name + "> already used" );
13762 
13763   memberData.name                                        = name;
13764   std::tie( memberData.arraySizes, memberData.bitCount ) = readModifiers( element->NextSibling() );
13765 }
13766 
readTypesTypeStructMemberType(tinyxml2::XMLElement const * element,MemberData & memberData)13767 void VulkanHppGenerator::readTypesTypeStructMemberType( tinyxml2::XMLElement const * element, MemberData & memberData )
13768 {
13769   int line = element->GetLineNum();
13770   checkAttributes( line, getAttributes( element ), {}, {} );
13771   checkElements( line, getChildElements( element ), {}, {} );
13772 
13773   memberData.type = readTypeInfo( element );
13774 }
13775 
readTypeInfo(tinyxml2::XMLElement const * element) const13776 VulkanHppGenerator::TypeInfo VulkanHppGenerator::readTypeInfo( tinyxml2::XMLElement const * element ) const
13777 {
13778   TypeInfo                  typeInfo;
13779   tinyxml2::XMLNode const * previousSibling = element->PreviousSibling();
13780   if ( previousSibling && previousSibling->ToText() )
13781   {
13782     typeInfo.prefix = trim( previousSibling->Value() );
13783   }
13784   typeInfo.type                         = element->GetText();
13785   tinyxml2::XMLNode const * nextSibling = element->NextSibling();
13786   if ( nextSibling && nextSibling->ToText() )
13787   {
13788     typeInfo.postfix = trimStars( trimEnd( nextSibling->Value() ) );
13789   }
13790   return typeInfo;
13791 }
13792 
registerDeleter(std::string const & name,std::pair<std::string,CommandData> const & commandData)13793 void VulkanHppGenerator::registerDeleter( std::string const & name, std::pair<std::string, CommandData> const & commandData )
13794 {
13795   if ( ( commandData.first.substr( 2, 7 ) == "Destroy" ) || ( commandData.first.substr( 2, 4 ) == "Free" ) )
13796   {
13797     std::string key;
13798     size_t      valueIndex;
13799     switch ( commandData.second.params.size() )
13800     {
13801       case 2:
13802       case 3:
13803         assert( commandData.second.params.back().type.type == "VkAllocationCallbacks" );
13804         key        = ( commandData.second.params.size() == 2 ) ? "" : commandData.second.params[0].type.type;
13805         valueIndex = commandData.second.params.size() - 2;
13806         break;
13807       case 4:
13808         key        = commandData.second.params[0].type.type;
13809         valueIndex = 3;
13810         assert( m_handles.find( commandData.second.params[valueIndex].type.type ) != m_handles.end() );
13811         m_handles.find( commandData.second.params[valueIndex].type.type )->second.deletePool = commandData.second.params[1].type.type;
13812         break;
13813       default: assert( false ); valueIndex = 0;
13814     }
13815     auto keyHandleIt = m_handles.find( key );
13816     assert( keyHandleIt != m_handles.end() );
13817     keyHandleIt->second.childrenHandles.insert( commandData.second.params[valueIndex].type.type );
13818 
13819     auto handleIt = m_handles.find( commandData.second.params[valueIndex].type.type );
13820     assert( handleIt != m_handles.end() );
13821     handleIt->second.deleteCommand = name;
13822   }
13823 }
13824 
rescheduleRAIIHandle(std::string & str,std::pair<std::string,HandleData> const & handle,std::set<std::string> & listedHandles,std::set<std::string> const & specialFunctions) const13825 void VulkanHppGenerator::rescheduleRAIIHandle( std::string &                              str,
13826                                                std::pair<std::string, HandleData> const & handle,
13827                                                std::set<std::string> &                    listedHandles,
13828                                                std::set<std::string> const &              specialFunctions ) const
13829 {
13830   listedHandles.insert( handle.first );
13831   if ( !handle.second.parent.empty() && ( listedHandles.find( handle.second.parent ) == listedHandles.end() ) )
13832   {
13833     auto parentIt = m_handles.find( handle.second.parent );
13834     assert( parentIt != m_handles.end() );
13835     str += generateRAIIHandle( *parentIt, listedHandles, specialFunctions );
13836   }
13837 
13838   for ( auto constructorIt : handle.second.constructorIts )
13839   {
13840     for ( auto const & param : constructorIt->second.params )
13841     {
13842       auto handleIt = m_handles.find( param.type.type );
13843       if ( handleIt != m_handles.end() && ( listedHandles.find( param.type.type ) == listedHandles.end() ) )
13844       {
13845         str += generateRAIIHandle( *handleIt, listedHandles, specialFunctions );
13846       }
13847     }
13848   }
13849 }
13850 
selectCommandsByHandle(std::vector<RequireData> const & requireData,std::set<std::string> const & handleCommands,std::set<std::string> & listedCommands) const13851 std::vector<std::string> VulkanHppGenerator::selectCommandsByHandle( std::vector<RequireData> const & requireData,
13852                                                                      std::set<std::string> const &    handleCommands,
13853                                                                      std::set<std::string> &          listedCommands ) const
13854 {
13855   std::vector<std::string> selectedCommands;
13856   for ( auto const & require : requireData )
13857   {
13858     for ( auto const & command : require.commands )
13859     {
13860       if ( ( handleCommands.find( command ) != handleCommands.end() ) && listedCommands.insert( command ).second )
13861       {
13862         selectedCommands.push_back( command );
13863       }
13864     }
13865   }
13866   return selectedCommands;
13867 }
13868 
setVulkanLicenseHeader(int line,std::string const & comment)13869 void VulkanHppGenerator::setVulkanLicenseHeader( int line, std::string const & comment )
13870 {
13871   checkForError( m_vulkanLicenseHeader.empty(), line, "second encounter of a Copyright comment" );
13872   m_vulkanLicenseHeader = comment;
13873 
13874   // replace any '\n' with "\n// "
13875   for ( size_t pos = m_vulkanLicenseHeader.find( '\n' ); pos != std::string::npos; pos = m_vulkanLicenseHeader.find( '\n', pos + 1 ) )
13876   {
13877     m_vulkanLicenseHeader.replace( pos, 1, "\n// " );
13878   }
13879   // remove any trailing spaces
13880   m_vulkanLicenseHeader = trimEnd( m_vulkanLicenseHeader );
13881 
13882   // and add a little message on our own
13883   m_vulkanLicenseHeader += "\n\n// This header is generated from the Khronos Vulkan XML API Registry.";
13884   m_vulkanLicenseHeader = trim( m_vulkanLicenseHeader ) + "\n";
13885 }
13886 
skipLeadingGrandParent(std::pair<std::string,HandleData> const & handle) const13887 bool VulkanHppGenerator::skipLeadingGrandParent( std::pair<std::string, HandleData> const & handle ) const
13888 {
13889   bool skip = false;
13890   assert( !handle.second.constructorIts.empty() );
13891   auto constructorIt = handle.second.constructorIts.begin();
13892   if ( ( 1 < ( *constructorIt )->second.params.size() ) && isHandleType( ( *constructorIt )->second.params[0].type.type ) &&
13893        ( ( *constructorIt )->second.params[1].type.type == handle.second.parent ) )
13894   {
13895     auto parentIt = m_handles.find( handle.second.parent );
13896     assert( parentIt != m_handles.end() );
13897     skip = ( ( *constructorIt )->second.params[0].type.type == parentIt->second.parent );
13898 #if !defined( NDEBUG )
13899     for ( auto it = std::next( constructorIt ); it != handle.second.constructorIts.end(); ++it )
13900     {
13901       assert( ( *it )->second.params[0].type.type == ( *constructorIt )->second.params[0].type.type );
13902       assert( !skip || ( ( *it )->second.params[1].type.type == ( *constructorIt )->second.params[1].type.type ) );
13903     }
13904 #endif
13905   }
13906   return skip;
13907 }
13908 
toString(TypeCategory category)13909 std::string VulkanHppGenerator::toString( TypeCategory category )
13910 {
13911   switch ( category )
13912   {
13913     case TypeCategory::Bitmask: return "bitmask";
13914     case TypeCategory::BaseType: return "basetype";
13915     case TypeCategory::Define: return "define";
13916     case TypeCategory::Enum: return "enum";
13917     case TypeCategory::FuncPointer: return "funcpointer";
13918     case TypeCategory::Handle: return "handle";
13919     case TypeCategory::Requires: return "requires";
13920     case TypeCategory::Struct: return "struct";
13921     case TypeCategory::Union: return "union";
13922     case TypeCategory::Unknown: return "unkown";
13923     default: assert( false ); return "";
13924   }
13925 }
13926 
addEnumAlias(int line,std::string const & name,std::string const & aliasName)13927 void VulkanHppGenerator::EnumData::addEnumAlias( int line, std::string const & name, std::string const & aliasName )
13928 {
13929   auto aliasIt = aliases.find( name );
13930   checkForError(
13931     ( aliasIt == aliases.end() ) || ( aliasIt->second.name == aliasName ), line, "enum alias <" + name + "> already listed for a different enum value" );
13932   aliases.insert( std::make_pair( name, EnumAliasData( aliasName, line ) ) );
13933 }
13934 
addEnumValue(int line,std::string const & valueName,std::string const & protect,bool bitpos,std::string const & extension)13935 void VulkanHppGenerator::EnumData::addEnumValue(
13936   int line, std::string const & valueName, std::string const & protect, bool bitpos, std::string const & extension )
13937 {
13938   auto valueIt = std::find_if( values.begin(), values.end(), [&valueName]( EnumValueData const & evd ) { return evd.name == valueName; } );
13939   if ( valueIt == values.end() )
13940   {
13941     values.emplace_back( line, valueName, protect, extension, bitpos );
13942   }
13943 }
13944 
compose(std::string const & nameSpace) const13945 std::string VulkanHppGenerator::TypeInfo::compose( std::string const & nameSpace ) const
13946 {
13947   return prefix + ( prefix.empty() ? "" : " " ) +
13948          ( nameSpace.empty() ? type : ( ( ( type.substr( 0, 2 ) == "Vk" ) ? ( nameSpace + "::" ) : "" ) + stripPrefix( type, "Vk" ) ) ) +
13949          ( postfix.empty() ? "" : " " ) + postfix;
13950 }
13951 
RequireData(int line,std::vector<std::string> const & depends_)13952 VulkanHppGenerator::RequireData::RequireData( int line, std::vector<std::string> const & depends_ ) : depends( depends_ ), xmlLine( line ) {}
13953 
13954 //
13955 // VulkanHppGenerator local functions
13956 //
13957 
13958 // check the validity of an attributes map
13959 // line       : the line in the xml file where the attributes are listed
13960 // attributes : the map of name/value pairs of the encountered attributes
13961 // required   : the required attributes, with a set of allowed values per attribute
13962 // optional   : the optional attributes, with a set of allowed values per attribute
checkAttributes(int line,std::map<std::string,std::string> const & attributes,std::map<std::string,std::set<std::string>> const & required,std::map<std::string,std::set<std::string>> const & optional)13963 void checkAttributes( int                                                  line,
13964                       std::map<std::string, std::string> const &           attributes,
13965                       std::map<std::string, std::set<std::string>> const & required,
13966                       std::map<std::string, std::set<std::string>> const & optional )
13967 {
13968   // check if all required attributes are included and if there is a set of allowed values, check if the actual
13969   // value is part of that set
13970   for ( auto const & r : required )
13971   {
13972     auto attributesIt = attributes.find( r.first );
13973     checkForError( attributesIt != attributes.end(), line, "missing attribute <" + r.first + ">" );
13974     if ( !r.second.empty() )
13975     {
13976       std::vector<std::string> values = tokenize( attributesIt->second, "," );
13977       for ( auto const & v : values )
13978       {
13979         checkForError( r.second.find( v ) != r.second.end(), line, "unexpected attribute value <" + v + "> in attribute <" + attributesIt->first + ">" );
13980       }
13981     }
13982   }
13983   // check if all not required attributes or optional, and if there is a set of allowed values, check if the
13984   // actual value is part of that set
13985   for ( auto const & a : attributes )
13986   {
13987     if ( required.find( a.first ) == required.end() )
13988     {
13989       auto optionalIt = optional.find( a.first );
13990       if ( optionalIt == optional.end() )
13991       {
13992         checkForWarning( false, line, "unknown attribute <" + a.first + ">" );
13993         continue;
13994       }
13995       if ( !optionalIt->second.empty() )
13996       {
13997         std::vector<std::string> values = tokenize( a.second, "," );
13998         for ( auto const & v : values )
13999         {
14000           checkForWarning(
14001             optionalIt->second.find( v ) != optionalIt->second.end(), line, "unexpected attribute value <" + v + "> in attribute <" + a.first + ">" );
14002         }
14003       }
14004     }
14005   }
14006 }
14007 
checkElements(int line,std::vector<tinyxml2::XMLElement const * > const & elements,std::map<std::string,bool> const & required,std::set<std::string> const & optional)14008 void checkElements( int                                               line,
14009                     std::vector<tinyxml2::XMLElement const *> const & elements,
14010                     std::map<std::string, bool> const &               required,
14011                     std::set<std::string> const &                     optional )
14012 {
14013   std::map<std::string, size_t> encountered;
14014   for ( auto const & e : elements )
14015   {
14016     std::string value = e->Value();
14017     encountered[value]++;
14018     checkForWarning(
14019       ( required.find( value ) != required.end() ) || ( optional.find( value ) != optional.end() ), e->GetLineNum(), "unknown element <" + value + ">" );
14020   }
14021   for ( auto const & r : required )
14022   {
14023     auto encounteredIt = encountered.find( r.first );
14024     checkForError( encounteredIt != encountered.end(), line, "missing required element <" + r.first + ">" );
14025     // check: r.second (means: required excactly once) => (encouteredIt->second == 1)
14026     checkForError( !r.second || ( encounteredIt->second == 1 ),
14027                    line,
14028                    "required element <" + r.first + "> is supposed to be listed exactly once, but is listed " + std::to_string( encounteredIt->second ) );
14029   }
14030 }
14031 
checkForError(bool condition,int line,std::string const & message)14032 void checkForError( bool condition, int line, std::string const & message )
14033 {
14034   if ( !condition )
14035   {
14036     throw std::runtime_error( "VulkanHppGenerator: Spec error on line " + std::to_string( line ) + ": " + message );
14037   }
14038 }
14039 
checkForWarning(bool condition,int line,std::string const & message)14040 void checkForWarning( bool condition, int line, std::string const & message )
14041 {
14042   if ( !condition )
14043   {
14044     std::cerr << "VulkanHppGenerator: Spec warning on line " << std::to_string( line ) << ": " << message << "!" << std::endl;
14045   }
14046 }
14047 
findTag(std::set<std::string> const & tags,std::string const & name,std::string const & postfix)14048 std::string findTag( std::set<std::string> const & tags, std::string const & name, std::string const & postfix )
14049 {
14050   auto tagIt = std::find_if( tags.begin(), tags.end(), [&name, &postfix]( std::string const & t ) { return name.ends_with( t + postfix ); } );
14051   return ( tagIt != tags.end() ) ? *tagIt : "";
14052 }
14053 
generateCArraySizes(std::vector<std::string> const & sizes)14054 std::string generateCArraySizes( std::vector<std::string> const & sizes )
14055 {
14056   std::string arraySizes;
14057   for ( auto const & s : sizes )
14058   {
14059     arraySizes += "[" + s + "]";
14060   }
14061   return arraySizes;
14062 }
14063 
generateEnumSuffixes(std::string const & name,bool bitmask,std::set<std::string> const & tags)14064 std::pair<std::string, std::string> generateEnumSuffixes( std::string const & name, bool bitmask, std::set<std::string> const & tags )
14065 {
14066   std::string prefix, postfix;
14067   if ( name == "VkResult" )
14068   {
14069     prefix = "VK_";
14070   }
14071   else
14072   {
14073     if ( bitmask )
14074     {
14075       // for a bitmask enum, start with "VK", cut off the trailing "FlagBits", and convert that name to upper case
14076       // end that with "Bit"
14077       size_t pos = name.find( "FlagBits" );
14078       assert( pos != std::string::npos );
14079       std::string shortenedName = name;
14080       shortenedName.erase( pos, strlen( "FlagBits" ) );
14081       std::string tag = findTag( tags, shortenedName );
14082       prefix          = toUpperCase( stripPostfix( shortenedName, tag ) ) + "_";
14083     }
14084     else
14085     {
14086       // for a non-bitmask enum, convert the name to upper case
14087       prefix = toUpperCase( name ) + "_";
14088     }
14089 
14090     // if the enum name contains a tag move it from the prefix to the postfix to generate correct enum value
14091     // names.
14092     for ( auto const & tag : tags )
14093     {
14094       if ( prefix.ends_with( tag + "_" ) )
14095       {
14096         prefix.erase( prefix.length() - tag.length() - 1 );
14097         postfix = "_" + tag;
14098         break;
14099       }
14100       else if ( name.ends_with( tag ) )
14101       {
14102         postfix = "_" + tag;
14103         break;
14104       }
14105     }
14106   }
14107 
14108   return std::make_pair( prefix, postfix );
14109 }
14110 
generateEnumValueName(std::string const & enumName,std::string const & valueName,bool bitmask,std::set<std::string> const & tags)14111 std::string generateEnumValueName( std::string const & enumName, std::string const & valueName, bool bitmask, std::set<std::string> const & tags )
14112 {
14113   std::string prefix, postfix;
14114   std::tie( prefix, postfix ) = generateEnumSuffixes( enumName, bitmask, tags );
14115   std::string tag             = findTag( tags, valueName, "" );
14116   if ( postfix == "_" + tag )
14117   {
14118     tag = findTag( tags, valueName, postfix );
14119   }
14120 
14121   std::string result = "e" + toCamelCase( stripPostfix( stripPrefix( valueName, prefix ), postfix ) );
14122   if ( bitmask )
14123   {
14124     size_t pos = result.find( "Bit" );
14125     if ( pos != std::string::npos )
14126     {
14127       result.erase( pos, 3 );
14128     }
14129   }
14130   if ( !tag.empty() && ( result.substr( result.length() - tag.length() ) == toCamelCase( tag ) ) )
14131   {
14132     result = result.substr( 0, result.length() - tag.length() ) + tag;
14133   }
14134   return result;
14135 }
14136 
generateNamespacedType(std::string const & type)14137 std::string generateNamespacedType( std::string const & type )
14138 {
14139   return type.starts_with( "Vk" ) ? ( "VULKAN_HPP_NAMESPACE::" + stripPrefix( type, "Vk" ) ) : type;
14140 }
14141 
generateNoDiscard(bool returnsSomething,bool multiSuccessCodes,bool multiErrorCodes)14142 std::string generateNoDiscard( bool returnsSomething, bool multiSuccessCodes, bool multiErrorCodes )
14143 {
14144   return ( returnsSomething || multiSuccessCodes ) ? "VULKAN_HPP_NODISCARD " : ( multiErrorCodes ? "VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS " : "" );
14145 }
14146 
generateStandardArray(std::string const & type,std::vector<std::string> const & sizes)14147 std::string generateStandardArray( std::string const & type, std::vector<std::string> const & sizes )
14148 {
14149   std::string arrayString = "std::array<" + type + "," + sizes.back() + ">";
14150   for ( size_t i = sizes.size() - 2; i < sizes.size(); i-- )
14151   {
14152     arrayString = "std::array<" + arrayString + "," + sizes[i] + ">";
14153   }
14154   return arrayString;
14155 }
14156 
generateStandardArrayWrapper(std::string const & type,std::vector<std::string> const & sizes)14157 std::string generateStandardArrayWrapper( std::string const & type, std::vector<std::string> const & sizes )
14158 {
14159   std::string arrayString = "VULKAN_HPP_NAMESPACE::ArrayWrapper" + std::to_string( sizes.size() ) + "D<" + type;
14160   for ( auto const & size : sizes )
14161   {
14162     arrayString += ", " + size;
14163   }
14164   arrayString += ">";
14165   return arrayString;
14166 }
14167 
generateSuccessCode(std::string const & code,std::set<std::string> const & tags)14168 std::string generateSuccessCode( std::string const & code, std::set<std::string> const & tags )
14169 {
14170   std::string tag = findTag( tags, code );
14171   // on each success code: prepend 'VULKAN_HPP_NAMESPACE::Result::e', strip "VK_" and a tag, convert it to camel
14172   // case, and add the tag again
14173   return "VULKAN_HPP_NAMESPACE::Result::e" + toCamelCase( stripPostfix( stripPrefix( code, "VK_" ), tag ) ) + tag;
14174 }
14175 
getAttributes(tinyxml2::XMLElement const * element)14176 std::map<std::string, std::string> getAttributes( tinyxml2::XMLElement const * element )
14177 {
14178   std::map<std::string, std::string> attributes;
14179   for ( auto attribute = element->FirstAttribute(); attribute; attribute = attribute->Next() )
14180   {
14181     assert( attributes.find( attribute->Name() ) == attributes.end() );
14182     attributes[attribute->Name()] = attribute->Value();
14183   }
14184   return attributes;
14185 }
14186 
14187 template <typename ElementContainer>
getChildElements(ElementContainer const * element)14188 std::vector<tinyxml2::XMLElement const *> getChildElements( ElementContainer const * element )
14189 {
14190   std::vector<tinyxml2::XMLElement const *> childElements;
14191   for ( tinyxml2::XMLElement const * childElement = element->FirstChildElement(); childElement; childElement = childElement->NextSiblingElement() )
14192   {
14193     childElements.push_back( childElement );
14194   }
14195   return childElements;
14196 }
14197 
readModifiers(tinyxml2::XMLNode const * node)14198 std::pair<std::vector<std::string>, std::string> readModifiers( tinyxml2::XMLNode const * node )
14199 {
14200   std::vector<std::string> arraySizes;
14201   std::string              bitCount;
14202   if ( node && node->ToText() )
14203   {
14204     // following the name there might be some array size
14205     std::string value = node->Value();
14206     assert( !value.empty() );
14207     if ( value[0] == '[' )
14208     {
14209       std::string::size_type endPos = 0;
14210       while ( endPos + 1 != value.length() )
14211       {
14212         std::string::size_type startPos = value.find( '[', endPos );
14213         checkForError( startPos != std::string::npos, node->GetLineNum(), "could not find '[' in <" + value + ">" );
14214         endPos = value.find( ']', startPos );
14215         checkForError( endPos != std::string::npos, node->GetLineNum(), "could not find ']' in <" + value + ">" );
14216         checkForError( startPos + 2 <= endPos, node->GetLineNum(), "missing content between '[' and ']' in <" + value + ">" );
14217         arraySizes.push_back( value.substr( startPos + 1, endPos - startPos - 1 ) );
14218       }
14219     }
14220     else if ( value[0] == ':' )
14221     {
14222       bitCount = value.substr( 1 );
14223     }
14224     else
14225     {
14226       checkForError( ( value[0] == ';' ) || ( value[0] == ')' ), node->GetLineNum(), "unknown modifier <" + value + ">" );
14227     }
14228   }
14229   return std::make_pair( arraySizes, bitCount );
14230 }
14231 
readSnippet(std::string const & snippetFile)14232 std::string readSnippet( std::string const & snippetFile )
14233 {
14234   std::ifstream ifs( std::string( BASE_PATH ) + "/snippets/" + snippetFile );
14235   assert( !ifs.fail() );
14236   std::ostringstream oss;
14237   oss << ifs.rdbuf();
14238   return oss.str();
14239 }
14240 
replaceWithMap(std::string const & input,std::map<std::string,std::string> replacements)14241 std::string replaceWithMap( std::string const & input, std::map<std::string, std::string> replacements )
14242 {
14243   // This will match ${someVariable} and contain someVariable in match group 1
14244   std::regex re( R"(\$\{([^\}]+)\})" );
14245   auto       it  = std::sregex_iterator( input.begin(), input.end(), re );
14246   auto       end = std::sregex_iterator();
14247 
14248   // No match, just return the original string
14249   if ( it == end )
14250   {
14251     assert( replacements.empty() );
14252     return input;
14253   }
14254 
14255 #if !defined( NDEBUG )
14256   std::set<std::string> matchedReplacements;
14257 #endif
14258 
14259   std::string result = "";
14260   while ( it != end )
14261   {
14262     std::smatch match         = *it;
14263     auto        itReplacement = replacements.find( match[1].str() );
14264     assert( itReplacement != replacements.end() );
14265 #if !defined( NDEBUG )
14266     matchedReplacements.insert( match[1].str() );
14267 #endif
14268 
14269     result += match.prefix().str() + ( ( itReplacement != replacements.end() ) ? itReplacement->second : match[0].str() );
14270     ++it;
14271 
14272     // we've passed the last match. Append the rest of the orignal string
14273     if ( it == end )
14274     {
14275       result += match.suffix().str();
14276     }
14277   }
14278 #if !defined( NDEBUG )
14279   std::set<std::string> missedReplacements;
14280   for ( auto r : replacements )
14281   {
14282     if ( matchedReplacements.find( r.first ) == matchedReplacements.end() )
14283     {
14284       missedReplacements.insert( r.first );
14285     }
14286   }
14287   assert( missedReplacements.empty() );
14288 #endif
14289   return result;
14290 }
14291 
startLowerCase(std::string const & input)14292 std::string startLowerCase( std::string const & input )
14293 {
14294   assert( !input.empty() );
14295   return static_cast<char>( tolower( input[0] ) ) + input.substr( 1 );
14296 }
14297 
startUpperCase(std::string const & input)14298 std::string startUpperCase( std::string const & input )
14299 {
14300   assert( !input.empty() );
14301   return static_cast<char>( toupper( input[0] ) ) + input.substr( 1 );
14302 }
14303 
stripPostfix(std::string const & value,std::string const & postfix)14304 std::string stripPostfix( std::string const & value, std::string const & postfix )
14305 {
14306   std::string strippedValue = value;
14307   if ( strippedValue.ends_with( postfix ) )
14308   {
14309     strippedValue.erase( strippedValue.length() - postfix.length() );
14310   }
14311   return strippedValue;
14312 }
14313 
stripPluralS(std::string const & name,std::set<std::string> const & tags)14314 std::string stripPluralS( std::string const & name, std::set<std::string> const & tags )
14315 {
14316   std::string strippedName = name;
14317   std::string tag          = findTag( tags, name );
14318   if ( strippedName.ends_with( "s" + tag ) )
14319   {
14320     size_t pos = strippedName.rfind( 's' );
14321     if ( ( 2 <= pos ) && ( strippedName.substr( pos - 2, 3 ) == "ies" ) )
14322     {
14323       strippedName.replace( pos - 2, 3, "y" );
14324     }
14325     else
14326     {
14327       strippedName.erase( pos, 1 );
14328     }
14329   }
14330   return strippedName;
14331 }
14332 
stripPrefix(std::string const & value,std::string const & prefix)14333 std::string stripPrefix( std::string const & value, std::string const & prefix )
14334 {
14335   std::string strippedValue = value;
14336   if ( strippedValue.starts_with( prefix ) )
14337   {
14338     strippedValue.erase( 0, prefix.length() );
14339   }
14340   return strippedValue;
14341 }
14342 
toCamelCase(std::string const & value)14343 std::string toCamelCase( std::string const & value )
14344 {
14345   assert( !value.empty() && ( isupper( value[0] ) || isdigit( value[0] ) ) );
14346   std::string result;
14347   result.reserve( value.size() );
14348   bool keepUpper = true;
14349   for ( auto c : value )
14350   {
14351     if ( c == '_' )
14352     {
14353       keepUpper = true;
14354     }
14355     else if ( isdigit( c ) )
14356     {
14357       keepUpper = true;
14358       result.push_back( c );
14359     }
14360     else if ( keepUpper )
14361     {
14362       result.push_back( c );
14363       keepUpper = false;
14364     }
14365     else
14366     {
14367       result.push_back( static_cast<char>( tolower( c ) ) );
14368     }
14369   }
14370   return result;
14371 }
14372 
toUpperCase(std::string const & name)14373 std::string toUpperCase( std::string const & name )
14374 {
14375   std::string convertedName;
14376   bool        previousIsLowerCase = false;
14377   bool        previousIsDigit     = false;
14378   for ( auto c : name )
14379   {
14380     if ( ( isupper( c ) && ( previousIsLowerCase || previousIsDigit ) ) || ( isdigit( c ) && previousIsLowerCase ) )
14381     {
14382       convertedName.push_back( '_' );
14383     }
14384     convertedName.push_back( static_cast<char>( toupper( c ) ) );
14385     previousIsLowerCase = !!islower( c );
14386     previousIsDigit     = !!isdigit( c );
14387   }
14388   return convertedName;
14389 }
14390 
tokenize(std::string const & tokenString,std::string const & separator)14391 std::vector<std::string> tokenize( std::string const & tokenString, std::string const & separator )
14392 {
14393   std::vector<std::string> tokens;
14394   if ( !tokenString.empty() )
14395   {
14396     size_t start = 0, end;
14397     do
14398     {
14399       end = tokenString.find( separator, start );
14400       if ( start != end )
14401       {
14402         tokens.push_back( trim( tokenString.substr( start, end - start ) ) );
14403       }
14404       start = end + separator.length();
14405     } while ( end != std::string::npos );
14406   }
14407   return tokens;
14408 }
14409 
tokenizeAny(std::string const & tokenString,std::string const & separators)14410 std::vector<std::string> tokenizeAny( std::string const & tokenString, std::string const & separators )
14411 {
14412   std::vector<std::string> tokens;
14413   if ( !tokenString.empty() )
14414   {
14415     size_t start = 0, end;
14416     do
14417     {
14418       end = tokenString.find_first_of( separators, start );
14419       if ( start != end )
14420       {
14421         tokens.push_back( trim( tokenString.substr( start, end - start ) ) );
14422       }
14423       start = end + 1;
14424     } while ( end != std::string::npos );
14425   }
14426   return tokens;
14427 }
14428 
trim(std::string const & input)14429 std::string trim( std::string const & input )
14430 {
14431   std::string result = input;
14432   result.erase( result.begin(), std::find_if( result.begin(), result.end(), []( char c ) { return !std::isspace( c ); } ) );
14433   result.erase( std::find_if( result.rbegin(), result.rend(), []( char c ) { return !std::isspace( c ); } ).base(), result.end() );
14434   return result;
14435 }
14436 
trimEnd(std::string const & input)14437 std::string trimEnd( std::string const & input )
14438 {
14439   std::string result = input;
14440   result.erase( std::find_if( result.rbegin(), result.rend(), []( char c ) { return !std::isspace( c ); } ).base(), result.end() );
14441   return result;
14442 }
14443 
trimStars(std::string const & input)14444 std::string trimStars( std::string const & input )
14445 {
14446   std::string result = input;
14447   size_t      pos    = result.find( '*' );
14448   while ( pos != std::string::npos )
14449   {
14450     if ( ( 0 < pos ) && ( result[pos - 1] != ' ' ) && ( result[pos - 1] != '*' ) )
14451     {
14452       result.insert( pos, 1, ' ' );
14453       ++pos;
14454     }
14455     else if ( ( pos < result.length() - 1 ) && ( result[pos + 1] != ' ' ) && ( result[pos + 1] != '*' ) )
14456     {
14457       result.insert( pos + 1, 1, ' ' );
14458     }
14459     pos = result.find( '*', pos + 1 );
14460   }
14461   return result;
14462 }
14463 
writeToFile(std::string const & str,std::string const & fileName)14464 void writeToFile( std::string const & str, std::string const & fileName )
14465 {
14466   std::ofstream ofs( fileName );
14467   assert( !ofs.fail() );
14468   ofs << str;
14469   ofs.close();
14470 
14471 #if defined( CLANG_FORMAT_EXECUTABLE )
14472   std::cout << "VulkanHppGenerator: Formatting " << fileName << " ..." << std::endl;
14473   std::string commandString = "\"" CLANG_FORMAT_EXECUTABLE "\" -i --style=file " + fileName;
14474   int         ret           = std::system( commandString.c_str() );
14475   if ( ret != 0 )
14476   {
14477     std::cout << "VulkanHppGenerator: failed to format file " << fileName << " with error <" << ret << ">\n";
14478   }
14479 #endif
14480 }
14481 
toString(tinyxml2::XMLError error)14482 std::string toString( tinyxml2::XMLError error )
14483 {
14484   switch ( error )
14485   {
14486     case tinyxml2::XML_SUCCESS: return "XML_SUCCESS";
14487     case tinyxml2::XML_NO_ATTRIBUTE: return "XML_NO_ATTRIBUTE";
14488     case tinyxml2::XML_WRONG_ATTRIBUTE_TYPE: return "XML_WRONG_ATTRIBUTE_TYPE";
14489     case tinyxml2::XML_ERROR_FILE_NOT_FOUND: return "XML_ERROR_FILE_NOT_FOUND";
14490     case tinyxml2::XML_ERROR_FILE_COULD_NOT_BE_OPENED: return "XML_ERROR_FILE_COULD_NOT_BE_OPENED";
14491     case tinyxml2::XML_ERROR_FILE_READ_ERROR: return "XML_ERROR_FILE_READ_ERROR";
14492     case tinyxml2::XML_ERROR_PARSING_ELEMENT: return "XML_ERROR_PARSING_ELEMENT";
14493     case tinyxml2::XML_ERROR_PARSING_ATTRIBUTE: return "XML_ERROR_PARSING_ATTRIBUTE";
14494     case tinyxml2::XML_ERROR_PARSING_TEXT: return "XML_ERROR_PARSING_TEXT";
14495     case tinyxml2::XML_ERROR_PARSING_CDATA: return "XML_ERROR_PARSING_CDATA";
14496     case tinyxml2::XML_ERROR_PARSING_COMMENT: return "XML_ERROR_PARSING_COMMENT";
14497     case tinyxml2::XML_ERROR_PARSING_DECLARATION: return "XML_ERROR_PARSING_DECLARATION";
14498     case tinyxml2::XML_ERROR_PARSING_UNKNOWN: return "XML_ERROR_PARSING_UNKNOWN";
14499     case tinyxml2::XML_ERROR_EMPTY_DOCUMENT: return "XML_ERROR_EMPTY_DOCUMENT";
14500     case tinyxml2::XML_ERROR_MISMATCHED_ELEMENT: return "XML_ERROR_MISMATCHED_ELEMENT";
14501     case tinyxml2::XML_ERROR_PARSING: return "XML_ERROR_PARSING";
14502     case tinyxml2::XML_CAN_NOT_CONVERT_TEXT: return "XML_CAN_NOT_CONVERT_TEXT";
14503     case tinyxml2::XML_NO_TEXT_NODE: return "XML_NO_TEXT_NODE";
14504     default: return "unknown error code <" + std::to_string( error ) + ">";
14505   }
14506 }
14507 
main(int argc,char ** argv)14508 int main( int argc, char ** argv )
14509 {
14510   try
14511   {
14512     tinyxml2::XMLDocument doc;
14513 
14514     std::string filename = ( argc == 1 ) ? VK_SPEC : argv[1];
14515 
14516 #if defined( CLANG_FORMAT_EXECUTABLE )
14517     std::cout << "VulkanHppGenerator: Found ";
14518     std::string commandString = "\"" CLANG_FORMAT_EXECUTABLE "\" --version ";
14519     int         ret           = std::system( commandString.c_str() );
14520     if ( ret != 0 )
14521     {
14522       std::cout << "VulkanHppGenerator: failed to determine clang_format version with error <" << ret << ">\n";
14523     }
14524 #endif
14525 
14526     std::cout << "VulkanHppGenerator: Loading " << filename << std::endl;
14527     tinyxml2::XMLError error = doc.LoadFile( filename.c_str() );
14528     if ( error != tinyxml2::XML_SUCCESS )
14529     {
14530       std::cout << "VulkanHppGenerator: failed to load file " << filename << " with error <" << toString( error ) << ">" << std::endl;
14531       return -1;
14532     }
14533 
14534     std::cout << "VulkanHppGenerator: Parsing " << filename << std::endl;
14535     VulkanHppGenerator generator( doc );
14536 
14537     generator.generateVulkanHppFile();
14538     generator.generateVulkanEnumsHppFile();
14539     generator.generateVulkanFormatTraitsHppFile();
14540     generator.prepareVulkanFuncs();
14541     generator.generateVulkanFuncsHppFile();
14542     generator.generateVulkanHandlesHppFile();
14543     generator.generateVulkanHashHppFile();
14544     generator.prepareRAIIHandles();
14545     generator.generateVulkanRAIIHppFile();
14546     generator.generateVulkanStaticAssertionsHppFile();
14547     generator.generateVulkanStructsHppFile();
14548     generator.generateVulkanToStringHppFile();
14549 
14550 #if !defined( CLANG_FORMAT_EXECUTABLE )
14551     std::cout << "VulkanHppGenerator: could not find clang-format. The generated files will not be formatted accordingly.\n";
14552 #endif
14553   }
14554   catch ( std::exception const & e )
14555   {
14556     std::cout << "caught exception: " << e.what() << std::endl;
14557     return -1;
14558   }
14559   catch ( ... )
14560   {
14561     std::cout << "caught unknown exception" << std::endl;
14562     return -1;
14563   }
14564 }
14565