1//
2// Copyright (C) 2024 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package main
18
19import (
20	"berberis/cpp_types"
21	"berberis/vulkan_types"
22	"berberis/vulkan_xml"
23	"errors"
24	"fmt"
25	"io"
26	"io/ioutil"
27	"os"
28	"path"
29	"sort"
30	"strings"
31)
32
33func main() {
34	var host_arch cpp_types.Arch
35	var guest_arch cpp_types.Arch
36	var vk_xml_filename string
37	var vulkan_xml_filename string
38	var custom_trampolines_filename string
39	args := os.Args[1:]
40	id := 0
41	for id < len(args) {
42		if args[id] == "--guest_arch" {
43			id++
44			switch {
45			case args[id] == "arm":
46				guest_arch = cpp_types.Arm
47			case args[id] == "arm64":
48				guest_arch = cpp_types.Arm64
49			case args[id] == "risvc32":
50				guest_arch = cpp_types.Riscv32
51			case args[id] == "riscv64":
52				guest_arch = cpp_types.Riscv64
53			case args[id] == "x86":
54				guest_arch = cpp_types.X86
55			case args[id] == "x86_64":
56				guest_arch = cpp_types.X86_64
57			}
58		} else if args[id] == "--host_arch" {
59			id++
60			switch {
61			case args[id] == "arm":
62				host_arch = cpp_types.Arm
63			case args[id] == "arm64":
64				host_arch = cpp_types.Arm64
65			case args[id] == "riscv32":
66				host_arch = cpp_types.Riscv32
67			case args[id] == "riscv64":
68				host_arch = cpp_types.Riscv64
69			case args[id] == "x86":
70				host_arch = cpp_types.X86
71			case args[id] == "x86_64":
72				host_arch = cpp_types.X86_64
73			}
74		} else if args[id] == "--input" {
75			id++
76			vk_xml_filename = args[id]
77		} else if args[id] == "--xml" {
78			id++
79			vulkan_xml_filename = args[id]
80		} else if args[id] == "--json" {
81			id++
82			custom_trampolines_filename = args[id]
83		} else {
84			panic(`
85Spurious arguments!
86
87Usage: gen_vulkan --input vk.xml --output vulkan_xml.h
88`)
89		}
90		id++
91	}
92
93	xmlFile, err := os.Open(vk_xml_filename)
94	if err != nil {
95		panic(err)
96	}
97	defer xmlFile.Close()
98
99	byteValue, _ := ioutil.ReadAll(xmlFile)
100
101	registry, err := vulkan_xml.Unmarshal(byteValue)
102	if err != nil {
103		panic(err)
104	}
105
106	sorted_type_names, types, sorted_command_names, commands, extensions, err := vulkan_xml.VulkanTypesfromXML(registry)
107	if err != nil {
108		panic(err)
109	}
110
111	if vulkan_xml_filename != "" {
112		err = generateVulkanXML(sorted_type_names, types, sorted_command_names, commands, extensions, vulkan_xml_filename, host_arch, guest_arch)
113		if err != nil {
114			panic(err)
115		}
116	}
117
118	if custom_trampolines_filename != "" {
119		err = generateCustomTrampolines(custom_trampolines_filename, sorted_command_names, commands, host_arch, guest_arch)
120		if err != nil {
121			panic(err)
122		}
123	}
124}
125
126func generateVulkanXML(sorted_type_names []string, types map[string]cpp_types.Type, sorted_command_names []string, commands map[string]cpp_types.Type, extensions map[string]int64, output_file_name string, host_arch, guest_arch cpp_types.Arch) error {
127
128	out_file, err := os.OpenFile(output_file_name, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
129	if err != nil {
130		return err
131	}
132	defer out_file.Close()
133
134	_, err = fmt.Fprintf(out_file,
135		`// This file is automatically generated by %s
136// DO NOT EDIT!
137
138// clang-format off
139
140`, path.Base(os.Args[0]))
141	if err != nil {
142		return err
143	}
144
145	sorted_struct_type_names, err := sortStructTypes(sorted_type_names, types)
146	if err != nil {
147		return err
148	}
149
150	err = printAliasTypes(out_file, sorted_type_names, types)
151	if err != nil {
152		return err
153	}
154
155	err = printEnums(out_file, sorted_type_names, types)
156	if err != nil {
157		return err
158	}
159
160	err = printEnumAliases(out_file, sorted_type_names, types)
161	if err != nil {
162		return err
163	}
164
165	conversions, err := getRequiredConversions(commands, types)
166	if err != nil {
167		return err
168	}
169
170	err = printHostStructTypes(out_file, sorted_struct_type_names, types)
171	if err != nil {
172		return err
173	}
174
175	err = printFunctionPointerTypes(out_file, sorted_command_names, commands)
176	if err != nil {
177		return err
178	}
179
180	_, err = fmt.Fprint(out_file, "#ifndef BERBERIS_LAYOUT_CHECK_ONLY\n")
181	if err != nil {
182		return err
183	}
184
185	err = printExtensionsMap(out_file, extensions)
186	if err != nil {
187		return err
188	}
189
190	_, err = fmt.Fprint(out_file, "}  // namespace\n\n")
191	if err != nil {
192		return err
193	}
194
195	err = printGuestStructTypes(out_file, sorted_struct_type_names, types, conversions, host_arch, guest_arch)
196	if err != nil {
197		return err
198	}
199
200	err = printConvertOptionalStructures(out_file, sorted_struct_type_names, types, conversions, host_arch, guest_arch)
201	if err != nil {
202		return err
203	}
204
205	_, err = fmt.Fprint(out_file,
206		`
207
208// Note: we put all the conversion routines in the anonymous namespace to make sure we are not
209// generating dead code or referencing non-existing code: attempt to use static function which
210// is not defined is error and if function is unreferenced that causes error since we are compiling
211// code with -Wunused-function -Werror options.
212//
213// But this requires definition certain stub functions in emulated_api_checker.cc
214
215namespace {
216
217// These trampolines and runners are too complex to be auto-generated.
218void DoCustomTrampolineWithThunk_vkAllocateCommandBuffers(HostCode callee, ProcessState* state);
219void DoCustomTrampolineWithThunk_vkBeginCommandBuffer(HostCode callee, ProcessState* state);
220void DoCustomTrampolineWithThunk_vkEnumerateDeviceExtensionProperties(HostCode callee, ProcessState* state);
221void DoCustomTrampolineWithThunk_vkEnumerateInstanceExtensionProperties(HostCode callee, ProcessState* state);
222void DoCustomTrampolineWithThunk_vkFreeCommandBuffers(HostCode callee, ProcessState* state);
223void DoCustomTrampolineWithThunk_vkGetDeviceProcAddr(HostCode callee, ProcessState* state);
224void DoCustomTrampolineWithThunk_vkGetInstanceProcAddr(HostCode callee, ProcessState* state);
225void RunGuest_vkEnumerateDeviceExtensionProperties(GuestAddr pc, GuestArgumentBuffer* buf);
226void RunGuest_vkEnumerateInstanceExtensionProperties(GuestAddr pc, GuestArgumentBuffer* buf);
227void RunGuest_vkCreateInstance(GuestAddr pc, GuestArgumentBuffer* buf);
228void RunGuest_vkGetDeviceProcAddr(GuestAddr pc, GuestArgumentBuffer* buf);
229void RunGuest_vkGetInstanceProcAddr(GuestAddr pc, GuestArgumentBuffer* buf);
230
231`)
232	if err != nil {
233		return err
234	}
235
236	err = printCustomTrampolies(out_file, sorted_command_names, commands, host_arch, guest_arch)
237	if err != nil {
238		return err
239	}
240
241	err = printCustomGuestRunners(out_file, sorted_command_names, commands, host_arch, guest_arch)
242	if err != nil {
243		return err
244	}
245
246	err = printMaps(out_file, sorted_command_names, commands, host_arch, guest_arch)
247	if err != nil {
248		return err
249	}
250
251	err = printGuestStructVerification(out_file, sorted_type_names, types, host_arch, guest_arch)
252	if err != nil {
253		return err
254	}
255
256	_, err = fmt.Fprintf(out_file,
257		`#endif  // BERBERIS_LAYOUT_CHECK_ONLY
258
259} // namespace
260
261}  // namespace berberis
262
263// Note: above we define all the Vulkan-related types that we are using, and don't rely on types
264// from official "vulkan.h" header.
265
266// This is because certain "official" types can only be used on certain platforms. E.g. you must be
267// on Windows platform to imclude Windows-specific types from vulkan_win32.h, you need OS with
268// Wayland support to use vulkan_wayland.h and so on.
269
270// The majority of types are platform-independent though thus comparing layout of our host-based
271// types to these is an excellent way to make sure our generator doesn't generate bogus type
272// definitions.
273
274#define VK_ENABLE_BETA_EXTENSIONS 1
275#include <vulkan/vk_android_native_buffer.h>
276#include <vulkan/vulkan.h>
277#include <vulkan/vulkan_android.h>
278#include <vulkan/vulkan_beta.h>
279
280`)
281	if err != nil {
282		return err
283	}
284
285	err = printAliasVerification(out_file, sorted_type_names, types, host_arch, guest_arch)
286	if err != nil {
287		return err
288	}
289
290	err = printEnumVerification(out_file, sorted_type_names, types, host_arch, guest_arch)
291	if err != nil {
292		return err
293	}
294
295	err = printHostStructVerification(out_file, sorted_type_names, types, host_arch, guest_arch)
296	if err != nil {
297		return err
298	}
299
300	_, err = fmt.Fprintf(out_file, "// clang-format on\n")
301	return err
302}
303
304func generateCustomTrampolines(output_file_name string, sorted_command_names []string, commands map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) (err error) {
305	out_file, err := os.OpenFile(output_file_name, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
306	if err != nil {
307		return err
308	}
309	defer out_file.Close()
310
311	symbols_list := []string{}
312	for _, name := range sorted_command_names {
313		command := commands[name]
314		params_are_compatible := true
315		switch name {
316		// These functions are compatible based on signatures, but actually need special processing.
317		case "vkGetDeviceProcAddr", "vkGetInstanceProcAddr":
318			params_are_compatible = false
319		}
320		for i := uint(0); i < command.NumField(guest_arch); i++ {
321			param_type := command.Field(i, guest_arch).Type()
322			if !isInputCompatible(param_type, host_arch, guest_arch) {
323				params_are_compatible = false
324				break
325			}
326		}
327		if !params_are_compatible {
328			symbols_list = append(symbols_list, fmt.Sprintf(`    "%s": {
329      "call_method": "custom_trampoline_with_thunk"
330    }`, name))
331		}
332	}
333	_, err = fmt.Fprintf(out_file, `{
334  "config": {
335    "ignore_non_present": true,
336    "reason": "some Vulkan functions are in drivers and are supported by our proxy while libvulkan.so lags behind"
337  },
338  "symbols": {
339%s
340  },
341  "types": {
342    "struct ANativeWindow": {
343      "force_compatible": true,
344      "reason_for_compatible": [
345        "This struct is full of function pointers ",
346        "which actually could be used by a guest code. ",
347        "It's too late to try to fix anything in ",
348        "Vulkan library though since these functions ",
349        "could be used before that point.  This must ",
350        "be handled by NativeActivity wrapper. "
351      ]
352    }
353  }
354}
355`,
356		strings.Join(symbols_list, ",\n"))
357	if err != nil {
358		return err
359	}
360	return err
361}
362
363func printAliasTypes(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type) (err error) {
364	printed_aliases := make(map[string]cpp_types.Type)
365	next_alias_types_list := []cpp_types.Type{}
366	for _, name := range sorted_type_names {
367		typе := types[name]
368		if vulkan_types.IsVulkanHandle(typе) {
369			_, err := fmt.Fprintf(w, "BERBERIS_VK_DEFINE_HANDLE(%s);\n\n", name)
370			if err != nil {
371				return err
372			}
373			printed_aliases[name] = typе
374		} else if vulkan_types.IsVulkanNondispatchableHandle(typе) {
375			_, err := fmt.Fprintf(w, "BERBERIS_VK_DEFINE_NON_DISPATCHABLE_HANDLE(%s);\n\n", name)
376			if err != nil {
377				return err
378			}
379			printed_aliases[name] = typе
380		} else if isAlias(typе) && !isAliasOfEnum(typе) {
381			base_name := typе.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch)
382			for arch := cpp_types.FirstArch + 1; arch <= cpp_types.LastArch; arch++ {
383				if base_name != typе.Elem(arch).Name(arch) {
384					return errors.New("Inconsistent alias \"" + name + "\"")
385				}
386			}
387			next_alias_types_list = append(next_alias_types_list, typе)
388		}
389	}
390	var alias_types_list []cpp_types.Type
391	for len(next_alias_types_list) > 0 {
392		// If next list is the same as previous one then we have some kind of loop and types couldn't be defined.
393		if len(alias_types_list) == len(next_alias_types_list) {
394			return errors.New("Cannot make any progress: type \"" + alias_types_list[0].Name(cpp_types.FirstArch) + "\" refers to undefined type: \"" + alias_types_list[0].Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch) + "\"\"")
395		}
396		alias_types_list = next_alias_types_list
397		next_alias_types_list = []cpp_types.Type{}
398		for _, typе := range alias_types_list {
399			if _, ok := printed_aliases[typе.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch)]; ok || !isAlias(typе.Elem(cpp_types.FirstArch)) {
400				name := typе.Name(cpp_types.FirstArch)
401				base_type := typе.Elem(cpp_types.FirstArch)
402				base_name := base_type.Name(cpp_types.FirstArch)
403				if isStruct(base_type) || isUnion(base_type) {
404					_, err := fmt.Fprintf(w, "%s;\n", base_name)
405					if err != nil {
406						return err
407					}
408				}
409				_, err := fmt.Fprintf(w, "using %s = %s;\n\n", name, base_name)
410				if err != nil {
411					return err
412				}
413				printed_aliases[name] = typе
414			} else {
415				next_alias_types_list = append(next_alias_types_list, typе)
416			}
417		}
418	}
419	return nil
420}
421
422func printAliasVerification(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) error {
423	for _, name := range sorted_type_names {
424		typе := types[name]
425		if !vulkan_types.IsVulkanHandle(typе) && !vulkan_types.IsVulkanNondispatchableHandle(typе) && !isAlias(typе) {
426			continue
427		}
428		if isAliasOfOpaque(typе) {
429			continue
430		}
431		_, err := fmt.Fprintf(
432			w,
433			`#if %[7]s
434CHECK_STRUCT_LAYOUT(berberis::%[2]s, %[3]d, %[4]d);
435#if !defined(BERBERIS_%[1]s)
436CHECK_STRUCT_LAYOUT(::%[2]s, %[3]d, %[4]d);
437#endif  /* BERBERIS_%[1]s */
438#elif %[8]s
439CHECK_STRUCT_LAYOUT(berberis::%[2]s, %[5]d, %[6]d);
440#if !defined(BERBERIS_%[1]s)
441CHECK_STRUCT_LAYOUT(::%[2]s, %[5]d, %[6]d);
442#endif  /* BERBERIS_%[1]s */
443#else
444#error Unsupported architecture.
445#endif
446
447`,
448			toEnumNameWithSuffix(name, "NOVERIFY"),
449			name,
450			typе.Bits(host_arch),
451			typе.Align(host_arch),
452			typе.Bits(guest_arch),
453			typе.Align(guest_arch),
454			cpp_types.Define(host_arch),
455			cpp_types.Define(guest_arch))
456		if err != nil {
457			return err
458		}
459	}
460	return nil
461}
462
463func printEnums(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type) (err error) {
464	for _, name := range sorted_type_names {
465		typе := types[name]
466		// Note: currently enums in vk.xml are architecture-agnostic. If some type is enum then it's always enum, on all
467		// architecturs.  And base type doesn't depend on the architecture either.
468		err := checkEnumConsistency(typе, name)
469		if err != nil {
470			return err
471		}
472		if !isEnum(typе) {
473			continue
474		}
475		_, err = fmt.Fprintf(w, "enum %s : %s {\n", name, typе.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch))
476		if err != nil {
477			return err
478		}
479		for i := uint(0); i < typе.NumField(cpp_types.FirstArch); i++ {
480			field := typе.Field(i, cpp_types.FirstArch).(cpp_types.EnumFieldInfo)
481			if field.Alias() == "" {
482				_, err = fmt.Fprintf(w, "  BERBERIS_%s = %d,\n", field.Name(), field.Value())
483				if err != nil {
484					return err
485				}
486			}
487		}
488		for i := uint(0); i < typе.NumField(cpp_types.FirstArch); i++ {
489			field := typе.Field(i, cpp_types.FirstArch).(cpp_types.EnumFieldInfo)
490			if field.Alias() != "" {
491				_, err = fmt.Fprintf(w, "  BERBERIS_%s = BERBERIS_%s,\n", field.Name(), field.Alias())
492				if err != nil {
493					return err
494				}
495			}
496		}
497		var maximum_value string
498		if isInt32T(typе.Elem(cpp_types.FirstArch)) {
499			maximum_value = "0x7FFF'FFFF"
500		} else if isUInt32T(typе.Elem(cpp_types.FirstArch)) {
501			maximum_value = "0xFFFF'FFFFU"
502		} else if isInt64T(typе.Elem(cpp_types.FirstArch)) {
503			maximum_value = "0x7FFF'FFFF'FFFF'FFFFULL"
504		} else {
505			return errors.New("Unknown enum base type definitions for type " + name)
506		}
507		_, err = fmt.Fprintf(w, "  BERBERIS_%s = %s\n};\n\n", toEnumNameWithSuffix(name, "MAX_ENUM"), maximum_value)
508		if err != nil {
509			return err
510		}
511	}
512	return nil
513}
514
515func printEnumVerification(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) error {
516	for _, name := range sorted_type_names {
517		typе := types[name]
518		// Note: currently enums in vk.xml are architecture-agnostic. If some type is enum then it's always enum, on all
519		// architectures.  And base type doesn't depend on the architecture either.
520		err := checkEnumConsistency(typе, name)
521		if err != nil {
522			return err
523		}
524		if !isEnum(typе) {
525			continue
526		}
527		_, err = fmt.Fprintf(
528			w,
529			`#if %[7]s
530CHECK_STRUCT_LAYOUT(berberis::%[2]s, %[3]d, %[4]d);
531#elif %[8]s
532CHECK_STRUCT_LAYOUT(berberis::%[2]s, %[5]d, %[6]d);
533#else
534#error Unsupported architecture.
535#endif
536#if !defined(BERBERIS_%[1]s)
537#if %[7]s
538CHECK_STRUCT_LAYOUT(::%[2]s, %[3]d, %[4]d);
539#elif %[8]s
540CHECK_STRUCT_LAYOUT(::%[2]s, %[5]d, %[6]d);
541#else
542#error Unsupported architecture.
543#endif
544`,
545			toEnumNameWithSuffix(name, "NOVERIFY"),
546			name,
547			typе.Bits(host_arch),
548			typе.Align(host_arch),
549			typе.Bits(guest_arch),
550			typе.Align(guest_arch),
551			cpp_types.Define(host_arch),
552			cpp_types.Define(guest_arch))
553		if err != nil {
554			return err
555		}
556		for i := uint(0); i < typе.NumField(cpp_types.FirstArch); i++ {
557			field := typе.Field(i, cpp_types.FirstArch).(cpp_types.EnumFieldInfo)
558			_, err = fmt.Fprintf(
559				w,
560				`#if !defined(BERBERIS_%[1]s_NOVERIFY)
561static_assert(std::int64_t(%[1]s) == std::int64_t(berberis::BERBERIS_%[1]s));
562#endif
563`,
564				field.Name())
565			if err != nil {
566				return err
567			}
568		}
569		_, err = fmt.Fprintf(
570			w,
571			`#if !defined(BERBERIS_%[2]s_NOVERIFY)
572static_assert(std::int64_t(%[2]s) == std::int64_t(berberis::BERBERIS_%[2]s));
573#endif  /* BERBERIS_%[2]s_NOVERIFY */
574#endif  /* BERBERIS_%[1]s */
575
576`,
577			toEnumNameWithSuffix(name, "NOVERIFY"),
578			toEnumNameWithSuffix(name, "MAX_ENUM"))
579		if err != nil {
580			return err
581		}
582	}
583	return nil
584}
585
586// Note: currently enums in vk.xml are architecture-agnostic. If some type is enum then it's always enum, on all
587// architectures.  And base type doesn't depend on the architecture either.
588//
589// Generators (above) rely on that property.
590func checkEnumConsistency(typе cpp_types.Type, name string) error {
591	if typе.Kind(cpp_types.FirstArch) != cpp_types.Enum {
592		for arch := cpp_types.FirstArch + 1; arch <= cpp_types.LastArch; arch++ {
593			if typе.Kind(arch) == cpp_types.Enum {
594				return errors.New("Inconsistent types definitions for type " + name)
595			}
596		}
597		return nil
598	}
599	if !isInputCompatible(typе, cpp_types.X86, cpp_types.Arm) || !isInputCompatible(typе, cpp_types.Arm64, cpp_types.X86_64) {
600		return errors.New("Inconsistent types definitions for type " + name)
601	}
602	return nil
603}
604
605func printEnumAliases(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type) (err error) {
606	// Note: currently enums in vk.xml are architecture-agnostic. If some type is enum then it's always enum, on all
607	// architecturs.  And base type doesn't depend on the architecture either.
608	//
609	// This simplifies the generation but we must verify that it's so to make sure this code would be adjusted in the
610	// [very unlikely] case where vk.xml would be changed to violate these invariants.
611	for _, name := range sorted_type_names {
612		typе := types[name]
613		if typе.Kind(cpp_types.FirstArch) != cpp_types.Alias || typе.Elem(cpp_types.FirstArch).Kind(cpp_types.FirstArch) != cpp_types.Enum {
614			for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
615				if typе.Kind(arch) == cpp_types.Alias && typе.Elem(cpp_types.FirstArch).Kind(cpp_types.FirstArch) == cpp_types.Enum {
616					return errors.New("Inconsistest types definitions for type " + name)
617				}
618			}
619			continue
620		} else {
621			for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
622				if typе.Kind(arch) != cpp_types.Alias || typе.Elem(cpp_types.FirstArch).Kind(cpp_types.FirstArch) != cpp_types.Enum {
623					return errors.New("Inconsistest types definitions for type " + name)
624				}
625				if typе.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch) != typе.Elem(arch).Name(arch) {
626					return errors.New("Inconsistest enum alias base type definitions for type " + name)
627				}
628			}
629		}
630		fmt.Fprintf(w, "using %s = %s;\n\n", name, typе.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch))
631	}
632	return nil
633}
634
635func sortStructTypes(sorted_type_names []string, types map[string]cpp_types.Type) (sorted_struct_types_names []string, err error) {
636	next_struct_names_list := []string{}
637	for _, name := range sorted_type_names {
638		typе := types[name]
639		if !isStruct(typе) && !isUnion(typе) {
640			continue
641		}
642		ids := typе.NumField(cpp_types.FirstArch)
643		for arch := cpp_types.FirstArch + 1; arch <= cpp_types.LastArch; arch++ {
644			if typе.Kind(cpp_types.FirstArch) != typе.Kind(arch) {
645				return nil, errors.New("Inconsistent struct \"" + name + "\"")
646			}
647			if ids != typе.NumField(arch) {
648				return nil, errors.New("Inconsistent struct \"" + name + "\"")
649			}
650			for id := uint(0); id < ids; id++ {
651				if typе.Field(id, cpp_types.FirstArch).Type().Name(cpp_types.FirstArch) != typе.Field(id, arch).Type().Name(arch) {
652					return nil, errors.New("Inconsistent struct \"" + name + "\"")
653				}
654			}
655		}
656		next_struct_names_list = append(next_struct_names_list, name)
657	}
658	sorted_struct_types_names = []string{}
659	declared_types := make(map[string]cpp_types.Type)
660	var struct_names_list []string
661	for len(next_struct_names_list) > 0 {
662		// If next list is the same as previous one then we have some kind of loop and types couldn't be defined.
663		if len(struct_names_list) == len(next_struct_names_list) {
664			return nil, errors.New("Cannot make any progress: type \"" + struct_names_list[0] + "\" refers to undefined type")
665		}
666		struct_names_list = next_struct_names_list
667		next_struct_names_list = []string{}
668	type_list:
669		for _, name := range struct_names_list {
670			typе := types[name]
671			ids := typе.NumField(cpp_types.FirstArch)
672			for id := uint(0); id < ids; id++ {
673				field_type := typе.Field(id, cpp_types.FirstArch).Type()
674				if !areBaseTypesDeclared(field_type, declared_types) {
675					next_struct_names_list = append(next_struct_names_list, name)
676					continue type_list
677				}
678			}
679			sorted_struct_types_names = append(sorted_struct_types_names, name)
680			declared_types[typе.Name(cpp_types.FirstArch)] = typе
681		}
682	}
683	return sorted_struct_types_names, nil
684}
685
686func areBaseTypesDeclared(typе cpp_types.Type, declared_types map[string]cpp_types.Type) bool {
687	if typе.Name(cpp_types.FirstArch) == "struct VkBaseInStructure" || typе.Name(cpp_types.FirstArch) == "struct VkBaseOutStructure" {
688		return true
689	}
690	for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
691		switch typе.Kind(arch) {
692		// If struct or union type is used then we need to have it declared.
693		// This is true both for Host and Guest types.
694		case cpp_types.Struct, cpp_types.Union:
695			if _, ok := declared_types[typе.Name(arch)]; !ok {
696				return false
697			}
698		// Aliases, Arrays, Consts don't change anything
699		case cpp_types.Alias, cpp_types.Array, cpp_types.Const:
700			if !areBaseTypesDeclared(typе.Elem(arch), declared_types) {
701				return false
702			}
703		// Pointers can be used with opaque structs, but it doesn't work if need to perform custom Host/Guest conversions.
704		case cpp_types.Ptr:
705			if !areBaseTypesDeclared(typе.Elem(arch), declared_types) {
706				return false
707			}
708		}
709	}
710	return true
711}
712
713func printHostStructTypes(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type) (err error) {
714	for _, name := range sorted_type_names {
715		if isStruct(types[name]) {
716			_, err = fmt.Fprintf(w, "struct %s;\n\n", name)
717		} else {
718			_, err = fmt.Fprintf(w, "union %s;\n\n", name)
719		}
720		if err != nil {
721			return err
722		}
723	}
724	for _, name := range sorted_type_names {
725		typе := types[name]
726		name := typе.Name(cpp_types.FirstArch)
727		_, err = fmt.Fprintf(w, "%s {\n", name)
728		if err != nil {
729			return err
730		}
731		ids := typе.NumField(cpp_types.FirstArch)
732		for id := uint(0); id < ids; id++ {
733			field_name := typе.Field(id, cpp_types.FirstArch).Name()
734			field_type := typе.Field(id, cpp_types.FirstArch).Type()
735			if isPtrToOpaque(field_type) {
736				// Assume opaque types are structs.
737				_, err = fmt.Fprintf(w, "  struct %s;\n", field_type.DeclareVar(field_name, cpp_types.FirstArch))
738			} else if isPtrToConstOpaque(field_type) {
739				// Assume opaque types are structs.
740				_, err = fmt.Fprintf(w, "  const struct %s;\n", cpp_types.PointerType(field_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch)).DeclareVar(field_name, cpp_types.FirstArch))
741			} else if isPtrToFunc(field_type) {
742				// Declare functions with BERBERIS_VKAPI_PTR attribute.
743				// This is needed if we want to use these on ARM platform because default Android API is
744				// “aapcs” but Vulkan needs “aapcs-vfp”.
745				_, err = fmt.Fprintf(w, "  %s;\n", field_type.Elem(cpp_types.FirstArch).DeclareVar(
746					fmt.Sprintf("(BERBERIS_VKAPI_PTR *%s)", field_name), cpp_types.FirstArch))
747			} else if isConstPtrToFunc(field_type) {
748				// Declare functions with BERBERIS_VKAPI_PTR attribute.
749				// This is needed if we want to use these on ARM platform because default Android API is
750				// “aapcs” but Vulkan needs “aapcs-vfp”.
751				_, err = fmt.Fprintf(w, "  %s;\n", field_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch).DeclareVar(
752					fmt.Sprintf("(BERBERIS_VKAPI_PTR *%sconst)", field_name), cpp_types.FirstArch))
753			} else {
754				_, err = fmt.Fprintf(w, "  %s;\n", field_type.DeclareVar(field_name, cpp_types.FirstArch))
755			}
756			if err != nil {
757				return err
758			}
759		}
760		_, err = fmt.Fprintf(w, "};\n\n")
761		if err != nil {
762			return err
763		}
764	}
765	return nil
766}
767
768func printFunctionPointerTypes(w io.Writer, sorted_command_names []string, commands map[string]cpp_types.Type) (err error) {
769	for _, name := range sorted_command_names {
770		_, err = fmt.Fprintf(w, "using PFN_%s = %s;\n", name, commands[name].DeclareVar("(BERBERIS_VKAPI_PTR*)", cpp_types.FirstArch))
771		if err != nil {
772			return err
773		}
774	}
775	return nil
776}
777
778func getRequiredConversions(commands map[string]cpp_types.Type, types map[string]cpp_types.Type) (conversion map[string]*NeededConvertor, err error) {
779	conversion = make(map[string]*NeededConvertor)
780	for name, _ := range types {
781		conversion[name] = &NeededConvertor{
782			need_base_convertor:        false,
783			need_array_convertor:       false,
784			need_const_convertor:       false,
785			need_const_array_convertor: false,
786		}
787	}
788	// We need convertors for types referred in functions (commands in Vulkan-speak) and all
789	// types which they refer too (transitively).
790	//
791	// We always have to handle all of them symmetrically because Layers require conversions
792	// in both directions.
793	for _, command := range commands {
794		for i := uint(0); i < command.NumField(cpp_types.FirstArch); i++ {
795			param_type := command.Field(i, cpp_types.FirstArch).Type()
796			if isPtrToAlias(param_type) {
797				param_type = cpp_types.PointerType(param_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch))
798			}
799			if isPtrToConstAlias(param_type) {
800				param_type = cpp_types.PointerType(cpp_types.ConstType(param_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch)))
801			}
802			param_length := command.Field(i, cpp_types.FirstArch).BaseFieldInfo().(vulkan_xml.ExtendedFieldInfo).Length()
803			if isPtrToConstStruct(param_type) {
804				base_name := param_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch).BaseName(cpp_types.FirstArch)
805				if param_length == nil {
806					conversion[base_name].need_const_convertor = true
807				} else if isPtr(param_length.Type()) {
808					return nil, errors.New("Unsupported combination of types for command")
809				} else {
810					if base_name == "VkDescriptorBufferBindingInfoEXT" {
811						// TODO(b/322902400): Make VkDescriptorBufferBindingInfoEXT work with berberis.
812					} else {
813						conversion[base_name].need_const_array_convertor = true
814					}
815				}
816			} else if isPtrToStruct(param_type) {
817				base_name := param_type.Elem(cpp_types.FirstArch).BaseName(cpp_types.FirstArch)
818				if param_length == nil {
819					if base_name == "VkGetLatencyMarkerInfoNV" {
820						// TODO(b/322902403): Make VkGetLatencyMarkerInfoNV work with berberis.
821					} else {
822						conversion[base_name].need_base_convertor = true
823					}
824				} else if isPtr(param_length.Type()) {
825					conversion[base_name].need_array_convertor = true
826				} else {
827					return nil, errors.New("Unsupported combination of types for command")
828				}
829			}
830		}
831	}
832	for {
833		attributes_changed := false
834		for name, typе := range types {
835			if !isStruct(typе) {
836				continue
837			}
838			ids := typе.NumField(cpp_types.FirstArch)
839			field_types := []cpp_types.Type{}
840			field_lengths := []cpp_types.FieldInfo{}
841			for id := uint(0); id < ids; id++ {
842				field_type := typе.Field(id, cpp_types.FirstArch).Type()
843				if isUnion(field_type) {
844					union_ids := field_type.NumField(cpp_types.FirstArch)
845					for union_id := uint(0); union_id < union_ids; union_id++ {
846						field_types = append(field_types, field_type.Field(union_id, cpp_types.FirstArch).Type())
847						field_lengths = append(field_lengths, field_type.Field(union_id, cpp_types.FirstArch).BaseFieldInfo().(vulkan_xml.ExtendedFieldInfo).Length())
848					}
849				} else {
850					field_types = append(field_types, field_type)
851					field_lengths = append(field_lengths, typе.Field(id, cpp_types.FirstArch).BaseFieldInfo().(vulkan_xml.ExtendedFieldInfo).Length())
852				}
853			}
854			if len(typе.(vulkan_xml.ExtendedStructInfo).ExtendedWith()) > 0 {
855				if typе.Field(0, cpp_types.FirstArch).Name() != "sType" {
856					return nil, errors.New("Extensible data structure without sType")
857				}
858				if typе.Field(1, cpp_types.FirstArch).Name() != "pNext" {
859					return nil, errors.New("Extensible data structure without pNext")
860				}
861				for _, extra_type := range typе.(vulkan_xml.ExtendedStructInfo).ExtendedWith() {
862					if isPtrToConst(typе.Field(1, cpp_types.FirstArch).Type()) {
863						field_types = append(field_types, cpp_types.PointerType(cpp_types.ConstType(extra_type)))
864					} else {
865						field_types = append(field_types, cpp_types.PointerType(extra_type))
866					}
867					field_lengths = append(field_lengths, nil)
868				}
869			}
870			for id, field_type := range field_types {
871				field_length := field_lengths[id]
872				if isPtrToAlias(field_type) {
873					field_type = cpp_types.PointerType(field_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch))
874				}
875				if isPtrToConstAlias(field_type) {
876					field_type = cpp_types.PointerType(cpp_types.ConstType(field_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch)))
877				}
878				if isPtrToConstStruct(field_type) {
879					base_type := field_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch)
880					base_name := base_type.BaseName(cpp_types.FirstArch)
881					if field_length == nil {
882						if (conversion[name].need_const_convertor || conversion[name].need_const_array_convertor) &&
883							!conversion[base_name].need_const_convertor {
884							if base_name == "VkFaultCallbackInfo" {
885								// TODO(b/322902053): Make VkFaultCallbackInfo work with berberis.
886							} else {
887								conversion[base_name].need_const_convertor = true
888								attributes_changed = true
889							}
890						}
891						// Optional data structures may be used both as inputs and outputs thus we can not rely on the constness of the "Next" pointer.
892						if conversion[name].need_base_convertor &&
893							!conversion[name].need_array_convertor &&
894							base_type.(vulkan_xml.ExtendedStructInfo).OptionalStruct() {
895							if !conversion[base_name].need_base_convertor {
896								conversion[base_name].need_base_convertor = true
897								attributes_changed = true
898							}
899						} else if conversion[name].need_base_convertor ||
900							conversion[name].need_array_convertor {
901							return nil, errors.New("Unsupported combination of types for struct")
902						}
903					} else if isPtr(field_length.Type()) {
904						return nil, errors.New("Unsupported combination of types for struct")
905					} else {
906						if (conversion[name].need_const_convertor || conversion[name].need_const_array_convertor) &&
907							!conversion[base_name].need_const_array_convertor {
908							conversion[base_name].need_const_array_convertor = true
909							attributes_changed = true
910						} else if conversion[name].need_base_convertor ||
911							conversion[name].need_array_convertor {
912							return nil, errors.New("Unsupported combination of types for struct")
913						}
914					}
915				} else if isPtrToStruct(field_type) {
916					base_type := field_type.Elem(cpp_types.FirstArch)
917					base_name := base_type.BaseName(cpp_types.FirstArch)
918					if base_name == "VkDescriptorBufferBindingPushDescriptorBufferHandleEXT" ||
919						base_name == "VkDrmFormatModifierProperties2EXT" ||
920						base_name == "VkDrmFormatModifierPropertiesEXT" ||
921						base_name == "VkRenderPassCreationFeedbackInfoEXT" ||
922						base_name == "VkRenderPassSubpassFeedbackInfoEXT" ||
923						base_name == "VkPhysicalDeviceLayeredApiPropertiesListKHR" {
924						// TODO(b/171255170): Process the optional structures correctly.
925					} else if base_name == "VkPipelineCreationFeedback" {
926						// VkPipelineCreationFeedback is referred from input data structure VkPipelineCreationFeedbackCreateInfo
927						if !conversion[base_name].need_base_convertor {
928							conversion[base_name].need_base_convertor = true
929							attributes_changed = true
930						}
931						if !conversion[base_name].need_array_convertor {
932							conversion[base_name].need_array_convertor = true
933							attributes_changed = true
934						}
935					} else if field_length == nil {
936						if (conversion[name].need_base_convertor || conversion[name].need_array_convertor) &&
937							!conversion[base_name].need_base_convertor {
938							conversion[base_name].need_base_convertor = true
939							attributes_changed = true
940						}
941						// Optional data structures may be used both as inputs and outputs thus we can not rely on the constness of the "Next" pointer.
942						if conversion[name].need_const_convertor &&
943							!conversion[name].need_const_array_convertor &&
944							base_type.(vulkan_xml.ExtendedStructInfo).OptionalStruct() {
945							if !conversion[base_name].need_const_convertor {
946								conversion[base_name].need_const_convertor = true
947								attributes_changed = true
948							}
949						} else if conversion[name].need_const_convertor ||
950							conversion[name].need_const_array_convertor {
951							return nil, errors.New("Unsupported combination of types for struct")
952						}
953					} else {
954						// We don't even try to handle nested out structures (except one case above).
955						if conversion[name].need_const_convertor ||
956							conversion[name].need_base_convertor ||
957							conversion[name].need_const_array_convertor ||
958							conversion[name].need_array_convertor {
959							return nil, errors.New("Unsupported combination of types for struct")
960						}
961					}
962				}
963			}
964		}
965		if !attributes_changed {
966			break
967		}
968	}
969	return conversion, nil
970}
971
972type NeededConvertor struct {
973	need_base_convertor        bool
974	need_array_convertor       bool
975	need_const_convertor       bool
976	need_const_array_convertor bool
977}
978
979func printGuestStructTypes(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type, conversion map[string]*NeededConvertor, host_arch, guest_arch cpp_types.Arch) (err error) {
980	for _, name := range sorted_type_names {
981		typе := types[name]
982		if isInputCompatible(typе, host_arch, guest_arch) {
983			continue
984		}
985		// The goal is to resolve issue with recursive structures like
986		// VkBaseInStructure/VkBaseOutStructure.
987		//
988		// These structures include pNext type which is not pointer to void
989		// (as usual), but point to the structures of the same type.
990		//
991		// Thus we have the following definition:
992		//
993		// template<>
994		// class GuestType<VkBaseOutStructure> {
995		//  public:
996		//   using Type = VkBaseOutStructure;
997		//
998		//   GuestType<VkStructureType> sType;
999		//   GuestType<struct VkBaseOutStructure*> pNext;
1000		// };
1001		//
1002		// It can only be processed if “class GuestType<VkBaseOutStructure*>” is defined
1003		// before “class GuestType<VkBaseOutStructure>”, but then we would have problem
1004		// with all conversion routines for “class GuestType<VkBaseOutStructure*>” since
1005		// these require access to “class GuestType<VkBaseOutStructure>”!
1006		//
1007		// Resolution is to declare “class GuestType<VkBaseOutStructure*>”, then declare
1008		// “class GuestType<VkBaseOutStructure>” and only then declare conversion routines.
1009		//
1010		err = printGuestStructPointerType(w, name, typе, host_arch, guest_arch, conversion)
1011		if err != nil {
1012			return err
1013		}
1014		err = printGuestStructType(w, name, typе, host_arch, guest_arch)
1015		if err != nil {
1016			return err
1017		}
1018		err = printGuestStructPointerConversionsType(w, name, typе, host_arch, guest_arch, conversion)
1019		if err != nil {
1020			return err
1021		}
1022	}
1023	return nil
1024}
1025
1026func printGuestStructType(w io.Writer, name string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) error {
1027	// Note: it's not possible to pass struct as an out argument in C (possible with C++ and references, but not with C)
1028	// and it looks as if GuestType<const StructType> is not needed (arguments of "const StructType" and "StructType"
1029	// are identical in C).
1030	//
1031	// But we need GuestType<StructType> and GuestType<const StructType> to handle the following corners case:
1032	// struct Foo {
1033	//   … ← here we have pointers, optional extensions or other complex data.
1034	// };
1035	// struct Bar {
1036	//   Foo foo;
1037	// };
1038	// void baz(Bar* bar);
1039	//
1040	// Here function baz returns struct “struct Bar” (using pointer argument) which embeds “struct Foo”.
1041	// Note that these structs can be nested few levels in depth.
1042	//
1043	// Here we effectively return value of type Foo (even if that's not possible, strictly speaking, in C) and the
1044	// simplest way is to keep origin and do conversion in destructor.
1045	//
1046	// That's not very efficient (we are keeping address which can, actually, be calculated) but that's simpler and,
1047	// thankfully, that's rare corner case, not the norm.
1048	for _, cоnst := range []string{"", "const "} {
1049		_, err := fmt.Fprintf(w, "template<>\nclass GuestType<%[1]s%[2]s> {\n public:\n  using Type = %[1]s%[2]s;\n\n", cоnst, name)
1050		if err != nil {
1051			return err
1052		}
1053		if isUnion(typе) {
1054			_, err := fmt.Fprintln(w, " union Union {")
1055			if err != nil {
1056				return err
1057			}
1058		}
1059		ids := typе.NumField(cpp_types.FirstArch)
1060		for id := uint(0); id < ids; id++ {
1061			field_name := typе.Field(id, cpp_types.FirstArch).Name()
1062			field_type := typе.Field(id, cpp_types.FirstArch).Type()
1063			if cоnst == "const " {
1064				if isArray(field_type) {
1065					field_type = cpp_types.ArrayType(cpp_types.ConstType(field_type.Elem(cpp_types.FirstArch)), field_type.NumField(cpp_types.FirstArch))
1066				} else {
1067					field_type = cpp_types.ConstType(field_type)
1068				}
1069			}
1070			if isPtrToOpaque(field_type) {
1071				// Assume opaque types are structs.
1072				_, err = fmt.Fprintf(w, "  GuestType<%sstruct %s> %s;\n", cоnst, field_type.Name(cpp_types.FirstArch), field_name)
1073			} else if isPtrToConstOpaque(field_type) {
1074				// Assume opaque types are structs.
1075				_, err = fmt.Fprintf(w, "  GuestType<const struct %s> %s;\n", cpp_types.PointerType(field_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch)).Name(cpp_types.FirstArch), field_name)
1076			} else if isPtrToFunc(field_type) {
1077				// Declare functions with BERBERIS_VKAPI_PTR attribute.
1078				// This is needed if we want to use these on ARM platform because default Android API is
1079				// “aapcs” but Vulkan needs “aapcs-vfp”.
1080				_, err = fmt.Fprintf(w, "  GuestType<%s> %s;\n", field_type.Elem(cpp_types.FirstArch).DeclareVar(
1081					"(BERBERIS_VKAPI_PTR*)", cpp_types.FirstArch), field_name)
1082			} else if isConstPtrToFunc(field_type) {
1083				// Declare functions with BERBERIS_VKAPI_PTR attribute.
1084				// This is needed if we want to use these on ARM platform because default Android API is
1085				// “aapcs” but Vulkan needs “aapcs-vfp”.
1086				_, err = fmt.Fprintf(w, "  GuestType<%s> %s;\n", field_type.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch).DeclareVar(
1087					"(BERBERIS_VKAPI_PTR*const)", cpp_types.FirstArch), field_name)
1088			} else if isArray(field_type) {
1089				elem := field_type.Elem(cpp_types.FirstArch)
1090				if isArray(elem) || isPtr(elem) {
1091					return errors.New("Array of complex type: " + field_type.Name(cpp_types.FirstArch))
1092				}
1093				_, err = fmt.Fprintf(w, "  GuestType<%s> %s[%d];\n", field_type.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch), field_name, field_type.NumField(cpp_types.FirstArch))
1094			} else if field_type.Align(host_arch) != field_type.Align(guest_arch) {
1095				_, err = fmt.Fprintf(w, "  alignas(%d) GuestType<%s> %s;\n", field_type.Align(guest_arch)/8, field_type.Name(cpp_types.FirstArch), field_name)
1096			} else {
1097				_, err = fmt.Fprintf(w, "  GuestType<%s> %s;\n", field_type.Name(cpp_types.FirstArch), field_name)
1098			}
1099			if err != nil {
1100				return err
1101			}
1102		}
1103		if isUnion(typе) {
1104			// Make the uniоn default-constructible by initializing first field. We need it to support holders.
1105			_, err := fmt.Fprintf(w, " } uniоn = { .%s = {} };\n", typе.Field(0, cpp_types.FirstArch).Name())
1106			if err != nil {
1107				return err
1108			}
1109		}
1110		_, err = fmt.Fprint(w, "};\n\n")
1111		if err != nil {
1112			return err
1113		}
1114	}
1115	return nil
1116}
1117
1118func printGuestStructPointerType(w io.Writer, name string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch, conversion map[string]*NeededConvertor) error {
1119	// Naked unions are never passed around in Vulkan. They are always embedded into structure with selector field.
1120	if isUnion(typе) {
1121		return nil
1122	}
1123
1124	// We are not trying to convert on ARM64 because we don't know if pointer is valid (and if all extensions are compatible).
1125	// On ARM32 we need to convert some data structures, but tests pass because of quirk of how they are run.
1126	// TODO(b/274875580): fix properly.
1127	if guest_arch == cpp_types.Arm64 && name == "VkCommandBufferInheritanceInfo" {
1128		return nil
1129	}
1130
1131	_, err := fmt.Fprintf(w, `template<>
1132class GuestType<%[1]s*> {
1133 public:
1134  using Type = %[1]s*;
1135  class GuestHolder;
1136  class GuestArrayHolder;
1137  class HostHolder;
1138  class HostArrayHolder;
1139  GuestType(%[1]s* const new_value, GuestHolder& holder, bool& out_of_memory);
1140  GuestType(%[1]s* const new_value, GuestArrayHolder& holder, const std::uint32_t* size, bool& out_of_memory);
1141  GuestType(GuestType<%[1]s>* const& new_value);
1142  GuestType(GuestType<%[1]s>*&& new_value);
1143  GuestType() = default;
1144  GuestType(const GuestType&) = default;
1145  GuestType(GuestType&&) = default;
1146  GuestType& operator=(const GuestType& data) = default;
1147  GuestType& operator=(GuestType&& data) = default;
1148  ~GuestType() = default;
1149`,
1150		name)
1151	if err != nil {
1152		return err
1153	}
1154
1155	if conversion[name].need_base_convertor {
1156		_, err = fmt.Fprintf(w, "  friend %[1]s* ToHostType(const GuestType&, HostHolder& holder, bool& out_of_memory);\n", name)
1157		if err != nil {
1158			return err
1159		}
1160	}
1161
1162	if conversion[name].need_array_convertor {
1163		_, err = fmt.Fprintf(w, "  friend %[1]s* ToHostType(const GuestType&, HostArrayHolder& holder, const std::uint32_t* size, bool& out_of_memory);\n", name)
1164		if err != nil {
1165			return err
1166		}
1167	}
1168
1169	_, err = fmt.Fprintf(w, `  friend GuestAddr ToGuestAddr(const GuestType& guest_type) { return guest_type.value_; }
1170
1171 private:
1172  GuestAddr value_;
1173};
1174
1175`)
1176	if err != nil {
1177		return err
1178	}
1179
1180	_, err = fmt.Fprintf(w, `template<>
1181class GuestType<const %[1]s*> {
1182 public:
1183  using Type = const %[1]s*;
1184  class GuestHolder;
1185  class GuestArrayHolder;
1186  class HostHolder;
1187  class HostArrayHolder;
1188  GuestType(const %[1]s* const new_value, GuestHolder& holder, bool& out_of_memory);
1189`,
1190		name)
1191	if err != nil {
1192		return err
1193	}
1194
1195	if name == "VkAccelerationStructureGeometryKHR" {
1196		_, err = fmt.Fprintf(w, "  GuestType(const VkAccelerationStructureGeometryKHR* const new_value, const VkAccelerationStructureGeometryKHR* const* const new_value_ptr, GuestArrayHolder& holder, std::size_t size, bool& out_of_memory);\n")
1197	} else {
1198		_, err = fmt.Fprintf(w, "  GuestType(const %[1]s* const new_value, GuestArrayHolder& holder, std::size_t size, bool& out_of_memory);\n", name)
1199	}
1200	if err != nil {
1201		return err
1202	}
1203
1204	_, err = fmt.Fprintf(w, `  GuestType(GuestType<const %[1]s>* const& new_value);
1205  GuestType(GuestType<const %[1]s>*&& new_value);
1206  GuestType(GuestType<%[1]s>* const& new_value);
1207  GuestType(GuestType<%[1]s>*&& new_value);
1208  GuestType() = default;
1209  GuestType(const GuestType&) = default;
1210  GuestType(GuestType&&) = default;
1211  GuestType& operator=(const GuestType& data) = default;
1212  GuestType& operator=(GuestType&& data) = default;
1213  ~GuestType() = default;
1214`,
1215		name)
1216	if err != nil {
1217		return err
1218	}
1219
1220	if conversion[name].need_const_convertor {
1221		if name == "VkCommandBufferBeginInfo" {
1222			_, err = fmt.Fprintf(w, "  friend const %[1]s* ToHostType(const GuestType&, HostHolder& holder, bool has_inheritance_info, bool& out_of_memory);\n", name)
1223		} else {
1224			_, err = fmt.Fprintf(w, "  friend const %[1]s* ToHostType(const GuestType&, HostHolder& holder, bool& out_of_memory);\n", name)
1225		}
1226		if err != nil {
1227			return err
1228		}
1229	}
1230
1231	if name == "VkAccelerationStructureGeometryKHR" {
1232		_, err = fmt.Fprintf(w, "  friend const %[1]s* ToHostType(const GuestType& new_value, GuestType<const VkAccelerationStructureGeometryKHR* const*> const new_value_ptr, HostArrayHolder& holder, std::size_t size, bool& out_of_memory);\n", name)
1233	} else if conversion[name].need_const_array_convertor {
1234		_, err = fmt.Fprintf(w, "  friend const %[1]s* ToHostType(const GuestType&, HostArrayHolder& holder, std::size_t size, bool& out_of_memory);\n", name)
1235	}
1236	if err != nil {
1237		return err
1238	}
1239
1240	_, err = fmt.Fprintf(w, `  friend GuestAddr ToGuestAddr(const GuestType& guest_type) { return guest_type.value_; }
1241
1242 private:
1243  GuestAddr value_;
1244};
1245
1246`)
1247	if err != nil {
1248		return err
1249	}
1250	return nil
1251}
1252
1253func printGuestStructPointerConversionsType(w io.Writer, name string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch, conversion map[string]*NeededConvertor) error {
1254	// Naked unions are never passed around in Vulkan. They are always embedded into structure with selector field.
1255	if isUnion(typе) {
1256		return nil
1257	}
1258
1259	// We are not trying to convert on ARM64 because we don't know if pointer is valid (and if all extensions are compatible).
1260	// On ARM32 we need to convert some data structures, but tests pass because of quirk of how they are run.
1261	// TODO(b/274875580): fix properly.
1262	if guest_arch == cpp_types.Arm64 && name == "VkCommandBufferInheritanceInfo" {
1263		return nil
1264	}
1265
1266	// Any data structure which have sType fields and pNext fields can be, potentially, expanded:
1267	//   https://github.com/KhronosGroup/Vulkan-Guide/blob/main/chapters/pnext_and_stype.adoc
1268	// We support extensions with data structures we are familiar with, but not unknown ones.
1269	extensible_type := isExtensibleType(typе)
1270
1271	_, err := fmt.Fprintf(w, `inline GuestType<%[1]s*>::GuestType(GuestType<%[1]s>* const& new_value) : value_(ToGuestAddr(new_value)) {}
1272inline GuestType<%[1]s*>::GuestType(GuestType<%[1]s>*&& new_value) : value_(ToGuestAddr(new_value)) {}
1273
1274inline GuestType<const %[1]s*>::GuestType(GuestType<const %[1]s>* const& new_value) : value_(ToGuestAddr(new_value)) {}
1275inline GuestType<const %[1]s*>::GuestType(GuestType<const %[1]s>*&& new_value) : value_(ToGuestAddr(new_value)) {}
1276inline GuestType<const %[1]s*>::GuestType(GuestType<%[1]s>* const& new_value) : value_(ToGuestAddr(new_value)) {}
1277inline GuestType<const %[1]s*>::GuestType(GuestType<%[1]s>*&& new_value) : value_(ToGuestAddr(new_value)) {}
1278
1279`,
1280		name)
1281	if err != nil {
1282		return err
1283	}
1284
1285	if conversion[name].need_base_convertor {
1286		if typе.(vulkan_xml.ExtendedStructInfo).OptionalStruct() {
1287			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::GuestHolder : public GuestHolderBase {
1288 public:
1289  virtual ~GuestHolder() override;
1290`,
1291				name)
1292		} else {
1293			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::GuestHolder {
1294 public:
1295  ~GuestHolder();
1296`,
1297				name)
1298		}
1299		if err != nil {
1300			return err
1301		}
1302		holder := ""
1303		if extensible_type {
1304			holder = "std::unique_ptr<GuestHolderBase> extensions_;\n  "
1305		}
1306		holder += "GuestType<" + name + "> data_;"
1307		if isInputCompatible(typе, host_arch, guest_arch) {
1308			_, err = fmt.Fprintf(w, `  friend GuestType<%[1]s*>;
1309
1310 private:
1311};
1312
1313inline GuestType<%[1]s*>::GuestHolder::~GuestHolder() {
1314}
1315
1316inline GuestType<%[1]s*>::GuestType(%[1]s* const new_value, GuestType<%[1]s*>::GuestHolder&, bool&) : value_(bit_cast<GuestAddr>(new_value)) {
1317}
1318
1319`,
1320				name)
1321		} else {
1322			_, err = fmt.Fprintf(w, `  friend GuestType<%[1]s*>;
1323
1324 private:
1325  friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1326  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1327  %[1]s* origin_ = nullptr;
1328  %[2]s
1329};
1330
1331inline GuestType<%[1]s*>::GuestHolder::~GuestHolder() {
1332  *origin_ = {
1333      %[3]s };
1334}
1335
1336inline GuestType<%[1]s*>::GuestType(%[1]s* const new_value, GuestType<%[1]s*>::GuestHolder& holder, [[maybe_unused]] bool& out_of_memory) : value_(new_value == nullptr ? kNullGuestAddr : ToGuestAddr(&holder.data_)) {
1337  holder.origin_ = new_value;
1338  holder.data_ = {
1339      %[4]s };
1340}
1341
1342`,
1343				name,
1344				strings.Join(append(
1345					makeHolderList("GuestType<%s>::Guest%sHolder %s_holder_;", false, typе, host_arch, guest_arch),
1346					holder), "\n  "),
1347				strings.Join(makeHostInitializerList(initializeDataMembers, name, typе, host_arch, guest_arch), "\n      "),
1348				strings.Join(makeGuestInitializerList(initializePointers, name, typе, host_arch, guest_arch), "\n      "))
1349		}
1350		if err != nil {
1351			return err
1352		}
1353		if typе.(vulkan_xml.ExtendedStructInfo).OptionalStruct() {
1354			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::HostHolder: HostHolderBase {
1355 public:
1356  virtual ~HostHolder() override;
1357`,
1358				name)
1359		} else {
1360			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::HostHolder {
1361 public:
1362  ~HostHolder();
1363`,
1364				name)
1365		}
1366		if err != nil {
1367			return err
1368		}
1369		holder = ""
1370		if extensible_type {
1371			holder = "std::unique_ptr<HostHolderBase> extensions_;\n  "
1372		}
1373		holder += name + " data_;"
1374		extra_holder_argument := ""
1375		if name == "VkCommandBufferBeginInfo" {
1376			extra_holder_argument = "bool has_inheritance_info, "
1377		}
1378		if isInputCompatible(typе, host_arch, guest_arch) {
1379			_, err = fmt.Fprintf(w, `  friend %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostHolder& holder, bool& out_of_memory);
1380
1381 private:
1382};
1383
1384inline GuestType<%[1]s*>::HostHolder::~HostHolder() {
1385}
1386
1387inline %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostHolder&, bool&) {
1388  return ToHostAddr<%[1]s>(ToGuestAddr(new_value));
1389}
1390
1391`,
1392				name)
1393		} else {
1394			_, err = fmt.Fprintf(w, `  friend %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostHolder& holder, bool& out_of_memory);
1395
1396 private:
1397  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
1398  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
1399  GuestType<%[1]s>* origin_ = nullptr;
1400  %[2]s
1401};
1402
1403inline GuestType<%[1]s*>::HostHolder::~HostHolder() {
1404  *origin_ = {
1405      %[3]s };
1406}
1407
1408inline %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostHolder& holder, %[5]s[[maybe_unused]] bool& out_of_memory) {
1409  if (ToGuestAddr(new_value) == kNullGuestAddr) {
1410    return nullptr;
1411  }
1412  holder.origin_ = ToHostAddr<GuestType<%[1]s>>(ToGuestAddr(new_value));
1413  holder.data_ = {
1414      %[4]s };
1415  return &holder.data_;
1416}
1417
1418`,
1419				name,
1420				strings.Join(append(
1421					makeHolderList("GuestType<%s>::Host%sHolder %s_holder_;", false, typе, host_arch, guest_arch),
1422					holder), "\n  "),
1423				strings.Join(makeGuestInitializerList(initializeDataMembers, name, typе, host_arch, guest_arch), "\n      "),
1424				strings.Join(makeHostInitializerList(initializePointers, name, typе, host_arch, guest_arch), "\n      "),
1425				extra_holder_argument)
1426		}
1427		if err != nil {
1428			return err
1429		}
1430	}
1431
1432	if conversion[name].need_array_convertor {
1433		holder := ""
1434		if extensible_type {
1435			holder = "std::unique_ptr<GuestHolderBase> extensions_;\n  "
1436		}
1437		holder += "GuestType<" + name + ">* data_ = nullptr;"
1438		if isInputCompatible(typе, host_arch, guest_arch) {
1439			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::GuestArrayHolder {
1440 public:
1441  ~GuestArrayHolder();
1442  friend GuestType<%[1]s*>;
1443
1444 private:
1445};
1446
1447inline GuestType<%[1]s*>::GuestArrayHolder::~GuestArrayHolder() {
1448}
1449
1450inline GuestType<%[1]s*>::GuestType(%[1]s* const new_value, GuestType<%[1]s*>::GuestArrayHolder&, const std::uint32_t*, bool&) : value_(bit_cast<GuestAddr>(new_value)) {
1451}
1452
1453`,
1454				name)
1455		} else {
1456			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::GuestArrayHolder {
1457 public:
1458  ~GuestArrayHolder();
1459  friend GuestType<%[1]s*>;
1460
1461 private:
1462  friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1463  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1464  const std::uint32_t* size_ = nullptr;
1465  %[1]s* origin_ = nullptr;
1466  %[2]s
1467};
1468
1469inline GuestType<%[1]s*>::GuestArrayHolder::~GuestArrayHolder() {
1470  if (size_ == nullptr) {
1471    return;
1472  }
1473  for (std::size_t index = 0; index < *size_; ++index) {
1474    origin_[index] = {
1475      %[5]s };
1476  }
1477  %[3]s
1478}
1479
1480// Note: for output data structures combo where “*size == 0” and yet data pointer is not nullptr is both valid and different from situation where data pointer is nullptr.
1481// Correct handling relies on obscure fact that “new Foo[0]” is also valid call in C++ and is guaranteed to produce non-nullptr pointer (which can not be dereferenced).
1482
1483inline GuestType<%[1]s*>::GuestType(%[1]s* const new_value, GuestType<%[1]s*>::GuestArrayHolder& holder, const std::uint32_t* size, [[maybe_unused]] bool& out_of_memory) : value_((new_value == nullptr) ? kNullGuestAddr : ToGuestAddr(holder.data_ = new (std::nothrow) GuestType<%[1]s>[*size])) {
1484  %[4]s
1485  for (std::size_t index = 0; index < *size; ++index) {
1486    ToHostAddr<GuestType<%[1]s>>(value_)[index] = {
1487      %[6]s };
1488  }
1489}
1490
1491`,
1492				name,
1493				strings.Join(append([]string{holder},
1494					// Note %s after * is to intentionally trigger error if/when arrays to arrays would occur in the output data structures.
1495					// TODO: read the documentation and fix the code if that would ever happen.
1496					makeHolderList("GuestType<%s>::GuestHolder*%s %s_holder_ = nullptr;", false, typе, host_arch, guest_arch)...), "\n  "),
1497				strings.Join(append(
1498					makeHolderList("delete[] %[3]s_holder_;", false, typе, host_arch, guest_arch),
1499					"delete[] data_;"), "\n  "),
1500				strings.Join(append([]string{"holder.origin_ = new_value;\n  if (value_ == kNullGuestAddr) {\n    if (new_value != nullptr) {\n      out_of_memory = true;\n    }\n    return;\n  }\n  holder.size_ = size;"},
1501					makeHolderList("if ((holder.%[3]s_holder_ = new (std::nothrow) GuestType<%[1]s>::GuestHolder%[2]s[*size]) == nullptr) {\n    out_of_memory = true;\n    return;\n  };", false, typе, host_arch, guest_arch)...), "\n  "),
1502				strings.Join(makeHostInitializerListForArray(initializeDataMembers, name, typе, host_arch, guest_arch), "\n      "),
1503				strings.Join(makeGuestInitializerListForArray(initializePointers, name, typе, host_arch, guest_arch), "\n      "))
1504		}
1505		if err != nil {
1506			return err
1507		}
1508
1509		holder = ""
1510		if extensible_type {
1511			holder = "std::unique_ptr<HostHolderBase> extensions_;\n  "
1512		}
1513		holder += name + "* data_ = nullptr;"
1514		if isInputCompatible(typе, host_arch, guest_arch) {
1515			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::HostArrayHolder {
1516 public:
1517  ~HostArrayHolder();
1518  friend %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostArrayHolder& holder, const std::uint32_t* size, bool& out_of_memory);
1519
1520 private:
1521};
1522
1523inline GuestType<%[1]s*>::HostArrayHolder::~HostArrayHolder() {
1524}
1525
1526inline %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostArrayHolder&, const std::uint32_t*, bool&) {
1527  return ToHostAddr<%[1]s>(ToGuestAddr(new_value));
1528}
1529
1530`,
1531				name)
1532		} else {
1533			_, err = fmt.Fprintf(w, `class GuestType<%[1]s*>::HostArrayHolder {
1534 public:
1535  ~HostArrayHolder();
1536  friend %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostArrayHolder& holder, const std::uint32_t* size, bool& out_of_memory);
1537
1538 private:
1539  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
1540  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
1541  const std::uint32_t* size_ = nullptr;
1542  GuestType<%[1]s>* origin_ = nullptr;
1543  %[2]s
1544};
1545
1546inline GuestType<%[1]s*>::HostArrayHolder::~HostArrayHolder() {
1547  if (size_ == nullptr) {
1548    return;
1549  }
1550  for (std::size_t index = 0; index < *size_; ++index) {
1551    origin_[index] = {
1552      %[5]s };
1553  }
1554  %[3]s
1555}
1556
1557inline %[1]s* ToHostType(const GuestType<%[1]s*>& new_value, GuestType<%[1]s*>::HostArrayHolder& holder, const std::uint32_t* size, bool& out_of_memory) {
1558  holder.origin_ = ToHostAddr<GuestType<%[1]s>>(ToGuestAddr(new_value));
1559  %[4]s
1560  for (std::size_t index = 0; index < *size; ++index) {
1561    holder.data_[index] = {
1562      %[6]s };
1563  }
1564  return holder.data_;
1565}
1566
1567`,
1568				name,
1569				strings.Join(append([]string{holder},
1570					// Note %s after * is to intentionally trigger error if/when arrays to arrays would occur in the output data structures.
1571					// TODO: read the documentation and fix the code if that would ever happen.
1572					makeHolderList("GuestType<%s>::HostHolder*%s %s_holder_ = nullptr;", false, typе, host_arch, guest_arch)...), "\n  "),
1573				strings.Join(append(
1574					makeHolderList("delete[] %[3]s_holder_;", false, typе, host_arch, guest_arch),
1575					"delete[] data_;"), "\n  "),
1576				strings.Join(append([]string{"if (ToGuestAddr(new_value) == kNullGuestAddr) {\n    return nullptr;\n  }\n  holder.size_ = size;\n  if ((holder.data_ = new (std::nothrow) " + name + "[*size]) == nullptr) {\n    out_of_memory = true;\n    return nullptr;\n  }"},
1577					makeHolderList("if ((holder.%[3]s_holder_ = new (std::nothrow) GuestType<%[1]s>::HostHolder%[2]s[*size]) == nullptr) {\n    out_of_memory = true;\n    return nullptr;\n  };", false, typе, host_arch, guest_arch)...), "\n  "),
1578				strings.Join(makeGuestInitializerListForArray(initializeDataMembers, name, typе, host_arch, guest_arch), "\n      "),
1579				strings.Join(makeHostInitializerListForArray(initializePointers, name, typе, host_arch, guest_arch), "\n      "))
1580		}
1581		if err != nil {
1582			return err
1583		}
1584	}
1585
1586	if conversion[name].need_const_convertor {
1587		if name == "VkAccelerationStructureBuildGeometryInfoKHR" {
1588			if isInputCompatible(typе, host_arch, guest_arch) {
1589				_, err = fmt.Fprintf(w, `class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestHolder {
1590 public:
1591  friend GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>;
1592
1593 private:
1594};
1595
1596inline GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestType(
1597    const VkAccelerationStructureBuildGeometryInfoKHR* new_value,
1598    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestHolder&,
1599    bool&)
1600    : value_(bit_cast<GuestAddr>(new_value)) {
1601}
1602
1603class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostHolder {
1604 public:
1605  friend const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
1606      const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
1607      GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostHolder& holder,
1608      bool& out_of_memory);
1609
1610 private:
1611};
1612
1613inline const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
1614    const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
1615    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostHolder&,
1616    bool&) {
1617  return ToHostAddr<VkAccelerationStructureBuildGeometryInfoKHR>(ToGuestAddr(new_value));
1618}
1619
1620`)
1621			} else {
1622				_, err = fmt.Fprintf(w, `class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestHolder {
1623 public:
1624  friend GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>;
1625
1626 private:
1627  friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1628  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1629  GuestType<const struct VkAccelerationStructureGeometryKHR*>::GuestArrayHolder pGeometries_holder_;
1630  std::unique_ptr<GuestHolderBase> extensions_;
1631  GuestType<VkAccelerationStructureBuildGeometryInfoKHR> data_;
1632};
1633
1634inline GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestType(
1635    const VkAccelerationStructureBuildGeometryInfoKHR* new_value,
1636    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestHolder& holder,
1637    bool& out_of_memory)
1638    : value_(new_value == nullptr ? kNullGuestAddr : ToGuestAddr(&holder.data_)) {
1639  if (new_value != nullptr) {
1640    holder.data_ = {
1641        .sType = GuestType<VkStructureType>(new_value->sType),
1642        .pNext = ConvertOptionalStructures(new_value->pNext, holder.extensions_, out_of_memory),
1643        .type = GuestType<VkAccelerationStructureTypeKHR>(new_value->type),
1644        .flags = GuestType<VkBuildAccelerationStructureFlagsKHR>(new_value->flags),
1645        .mode = GuestType<VkBuildAccelerationStructureModeKHR>(new_value->mode),
1646        .srcAccelerationStructure =
1647            GuestType<VkAccelerationStructureKHR>(new_value->srcAccelerationStructure),
1648        .dstAccelerationStructure =
1649            GuestType<VkAccelerationStructureKHR>(new_value->dstAccelerationStructure),
1650        .geometryCount = GuestType<std::uint32_t>(new_value->geometryCount),
1651        .pGeometries =
1652            GuestType<const struct VkAccelerationStructureGeometryKHR*>(new_value->pGeometries,
1653                                                                        new_value->ppGeometries,
1654                                                                        holder.pGeometries_holder_,
1655                                                                        new_value->geometryCount,
1656                                                                        out_of_memory),
1657        .ppGeometries =
1658            GuestType<const struct VkAccelerationStructureGeometryKHR* const*>(nullptr)};
1659  }
1660}
1661
1662class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostHolder {
1663 public:
1664  friend const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
1665      const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
1666      GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostHolder& holder,
1667      bool& out_of_memory);
1668
1669 private:
1670  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
1671  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
1672  GuestType<const struct VkAccelerationStructureGeometryKHR*>::HostArrayHolder pGeometries_holder_;
1673  std::unique_ptr<HostHolderBase> extensions_;
1674  VkAccelerationStructureBuildGeometryInfoKHR data_;
1675};
1676
1677inline const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
1678    const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
1679    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostHolder& holder,
1680    bool& out_of_memory) {
1681  if (ToGuestAddr(new_value) == kNullGuestAddr) {
1682    return nullptr;
1683  }
1684  holder.data_ = {
1685      .sType = VkStructureType(
1686          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1687              ->sType),
1688      .pNext = ConvertOptionalStructures(
1689          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1690              ->pNext,
1691          holder.extensions_,
1692          out_of_memory),
1693      .type = VkAccelerationStructureTypeKHR(
1694          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1695              ->type),
1696      .flags = VkBuildAccelerationStructureFlagsKHR(
1697          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1698              ->flags),
1699      .mode = VkBuildAccelerationStructureModeKHR(
1700          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1701              ->mode),
1702      .srcAccelerationStructure = VkAccelerationStructureKHR(
1703          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1704              ->srcAccelerationStructure),
1705      .dstAccelerationStructure = VkAccelerationStructureKHR(
1706          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1707              ->dstAccelerationStructure),
1708      .geometryCount = std::uint32_t(
1709          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1710              ->geometryCount),
1711      .pGeometries = ToHostType(
1712          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1713              ->pGeometries,
1714          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1715              ->ppGeometries,
1716          holder.pGeometries_holder_,
1717          ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(ToGuestAddr(new_value))
1718              ->geometryCount,
1719          out_of_memory),
1720      .ppGeometries = nullptr};
1721  return &holder.data_;
1722}
1723
1724`)
1725			}
1726			if err != nil {
1727				return err
1728			}
1729		} else {
1730			if typе.(vulkan_xml.ExtendedStructInfo).OptionalStruct() {
1731				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::GuestHolder: GuestHolderBase {
1732 public:
1733  virtual ~GuestHolder() override = default;
1734`,
1735					name)
1736			} else {
1737				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::GuestHolder {
1738 public:
1739`,
1740					name)
1741			}
1742			if err != nil {
1743				return err
1744			}
1745			if name == "VkDescriptorGetInfoEXT" {
1746				if isInputCompatible(typе, host_arch, guest_arch) {
1747					_, err = fmt.Fprintf(w, `  friend GuestType<const VkDescriptorGetInfoEXT*>;
1748
1749 private:
1750};
1751
1752inline GuestType<const VkDescriptorGetInfoEXT*>::GuestType(
1753    const VkDescriptorGetInfoEXT* new_value,
1754    GuestType<const VkDescriptorGetInfoEXT*>::GuestHolder&,
1755    bool&)
1756    : value_(bit_cast<GuestAddr>(new_value)) {}
1757
1758#endif
1759
1760`)
1761				} else {
1762					_, err = fmt.Fprintf(w, `  friend GuestType<const VkDescriptorGetInfoEXT*>;
1763
1764 private:
1765  friend GuestType<void*> ConvertOptionalStructures(void* head,
1766                                                    std::unique_ptr<GuestHolderBase>& holder,
1767                                                    bool& out_of_memory);
1768  friend GuestType<const void*> ConvertOptionalStructures(const void* head,
1769                                                          std::unique_ptr<GuestHolderBase>& holder,
1770                                                          bool& out_of_memory);
1771#if defined(__i386__)
1772  GuestType<const struct VkDescriptorImageInfo*>::GuestHolder VkDescriptorImageInfo_holder_;
1773#endif
1774  GuestType<const struct VkDescriptorAddressInfoEXT*>::GuestHolder
1775      VkDescriptorAddressInfoEXT_holder_;
1776  std::unique_ptr<GuestHolderBase> extensions_;
1777  GuestType<VkDescriptorGetInfoEXT> data_;
1778};
1779
1780inline GuestType<const VkDescriptorGetInfoEXT*>::GuestType(
1781    const VkDescriptorGetInfoEXT* new_value,
1782    GuestType<const VkDescriptorGetInfoEXT*>::GuestHolder& holder,
1783    [[maybe_unused]] bool& out_of_memory)
1784    : value_(new_value == nullptr ? kNullGuestAddr : ToGuestAddr(&holder.data_)) {
1785  if (new_value != nullptr) {
1786    holder.data_ = {
1787        .sType = GuestType<VkStructureType>(new_value->sType),
1788        .pNext = ConvertOptionalStructures(new_value->pNext, holder.extensions_, out_of_memory),
1789        .type = GuestType<VkDescriptorType>(new_value->type),
1790        .data =
1791            new_value->type == BERBERIS_VK_DESCRIPTOR_TYPE_SAMPLER
1792                ? GuestType<VkDescriptorDataEXT>{.uniоn = {.pSampler = GuestType<const VkSampler*>(
1793                                                               new_value->data.pSampler)}}
1794            : new_value->type == BERBERIS_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
1795                    new_value->type == BERBERIS_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ||
1796                    new_value->type == BERBERIS_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
1797                    new_value->type == BERBERIS_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
1798#if defined(__i386__)
1799                ? GuestType<VkDescriptorDataEXT>{.uniоn =
1800                                                     {.pSampledImage =
1801                                                          GuestType<const VkDescriptorImageInfo*>(
1802                                                              new_value->data.pSampledImage,
1803                                                              holder.VkDescriptorImageInfo_holder_,
1804                                                              out_of_memory)}}
1805#else
1806                ? GuestType<VkDescriptorDataEXT>{
1807                      .uniоn = {.pSampledImage = bit_cast<GuestType<const VkDescriptorImageInfo*>>(
1808                                    GuestType<const VkDescriptorImageInfo*>(
1809                                        new_value->data.pSampledImage))}}
1810#endif
1811            : new_value->type == BERBERIS_VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ||
1812                    new_value->type == BERBERIS_VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV
1813                ? GuestType<VkDescriptorDataEXT>{.uniоn = {.accelerationStructure =
1814                                                               GuestType<VkDeviceAddress>(
1815                                                                   new_value->data
1816                                                                       .accelerationStructure)}}
1817                : GuestType<VkDescriptorDataEXT>{
1818                      .uniоn = {.pUniformBuffer = GuestType<const VkDescriptorAddressInfoEXT*>(
1819                                    new_value->data.pUniformBuffer,
1820                                    holder.VkDescriptorAddressInfoEXT_holder_,
1821                                    out_of_memory)}}};
1822  }
1823}
1824
1825`)
1826				}
1827			} else {
1828				holder := ""
1829				if extensible_type {
1830					holder = "std::unique_ptr<GuestHolderBase> extensions_;\n  "
1831				}
1832				holder += "GuestType<" + name + "> data_;"
1833				if isInputCompatible(typе, host_arch, guest_arch) {
1834					_, err = fmt.Fprintf(w, `  friend GuestType<const %[1]s*>;
1835
1836 private:
1837};
1838
1839inline GuestType<const %[1]s*>::GuestType(const %[1]s* new_value, GuestType<const %[1]s*>::GuestHolder&, bool&) : value_(bit_cast<GuestAddr>(new_value))  {
1840}
1841
1842`,
1843						name)
1844				} else {
1845					_, err = fmt.Fprintf(w, `  friend GuestType<const %[1]s*>;
1846
1847 private:
1848  friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1849  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
1850  %[2]s
1851};
1852
1853inline GuestType<const %[1]s*>::GuestType(const %[1]s* new_value, GuestType<const %[1]s*>::GuestHolder& holder, [[maybe_unused]] bool& out_of_memory) : value_(new_value == nullptr ? kNullGuestAddr : ToGuestAddr(&holder.data_))  {
1854  if (new_value != nullptr) {
1855    holder.data_ = {
1856        %[3]s };
1857  }
1858}
1859
1860`,
1861						name,
1862						strings.Join(append(
1863							makeHolderList("GuestType<%s>::Guest%sHolder %s_holder_;", true, typе, host_arch, guest_arch),
1864							holder), "\n  "),
1865						strings.Join(makeGuestInitializerList(initializeConstStruct, name, typе, host_arch, guest_arch), "\n        "))
1866				}
1867			}
1868			if err != nil {
1869				return err
1870			}
1871			if typе.(vulkan_xml.ExtendedStructInfo).OptionalStruct() {
1872				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::HostHolder: public HostHolderBase {
1873 public:
1874  virtual ~HostHolder() override = default;
1875`,
1876					name)
1877			} else {
1878				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::HostHolder {
1879 public:
1880`,
1881					name)
1882			}
1883			if err != nil {
1884				return err
1885			}
1886			if name == "VkDescriptorGetInfoEXT" {
1887				if isInputCompatible(typе, host_arch, guest_arch) {
1888					_, err = fmt.Fprintf(w, `  friend const VkDescriptorGetInfoEXT* ToHostType(
1889      const GuestType<const VkDescriptorGetInfoEXT*>& new_value,
1890      GuestType<const VkDescriptorGetInfoEXT*>::HostHolder& holder,
1891      bool& out_of_memory);
1892
1893 private:
1894};
1895
1896inline const VkDescriptorGetInfoEXT* ToHostType(
1897    const GuestType<const VkDescriptorGetInfoEXT*>& new_value,
1898    GuestType<const VkDescriptorGetInfoEXT*>::HostHolder&,
1899    bool&) {
1900  return ToHostAddr<const VkDescriptorGetInfoEXT>(ToGuestAddr(new_value));
1901}
1902
1903`)
1904				} else {
1905					_, err = fmt.Fprintf(w, `  friend const VkDescriptorGetInfoEXT* ToHostType(
1906      const GuestType<const VkDescriptorGetInfoEXT*>& new_value,
1907      GuestType<const VkDescriptorGetInfoEXT*>::HostHolder& holder,
1908      bool& out_of_memory);
1909
1910 private:
1911  friend void* ConvertOptionalStructures(GuestType<void*> head,
1912                                         std::unique_ptr<HostHolderBase>& holder,
1913                                         bool& out_of_memory);
1914  friend const void* ConvertOptionalStructures(GuestType<const void*> head,
1915                                               std::unique_ptr<HostHolderBase>& holder,
1916                                               bool& out_of_memory);
1917#if defined(__i386__)
1918  GuestType<const struct VkDescriptorImageInfo*>::HostHolder VkDescriptorImageInfo_holder_;
1919#endif
1920  GuestType<const struct VkDescriptorAddressInfoEXT*>::HostHolder
1921      VkDescriptorAddressInfoEXT_holder_;
1922  std::unique_ptr<HostHolderBase> extensions_;
1923  VkDescriptorGetInfoEXT data_;
1924};
1925
1926inline const VkDescriptorGetInfoEXT* ToHostType(
1927    const GuestType<const VkDescriptorGetInfoEXT*>& new_value,
1928    GuestType<const VkDescriptorGetInfoEXT*>::HostHolder& holder,
1929    [[maybe_unused]] bool& out_of_memory) {
1930  if (ToGuestAddr(new_value) == kNullGuestAddr) {
1931    return nullptr;
1932  }
1933  holder.data_ = {
1934      .sType = VkStructureType(
1935          ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))->sType),
1936      .pNext = ConvertOptionalStructures(
1937          ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))->pNext,
1938          holder.extensions_,
1939          out_of_memory),
1940      .type = VkDescriptorType(
1941          ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))->type),
1942      .data =
1943          VkDescriptorType(
1944              ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))->type) ==
1945                  BERBERIS_VK_DESCRIPTOR_TYPE_SAMPLER
1946              ? VkDescriptorDataEXT{.pSampler = ToHostAddr<const VkSampler>(
1947                                        ToGuestAddr(ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(
1948                                                        ToGuestAddr(new_value))
1949                                                        ->data.uniоn.pSampler))}
1950          : VkDescriptorType(
1951                ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))->type) ==
1952                      BERBERIS_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
1953                  VkDescriptorType(
1954                      ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))
1955                          ->type) == BERBERIS_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ||
1956                  VkDescriptorType(
1957                      ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))
1958                          ->type) == BERBERIS_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
1959                  VkDescriptorType(
1960                      ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))
1961                          ->type) == BERBERIS_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
1962#if defined(__i386__)
1963              ? VkDescriptorDataEXT{.pSampledImage =
1964                                        ToHostType(ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(
1965                                                       ToGuestAddr(new_value))
1966                                                       ->data.uniоn.pSampledImage,
1967                                                   holder.VkDescriptorImageInfo_holder_,
1968                                                   out_of_memory)}
1969#else
1970              ? VkDescriptorDataEXT{
1971                  .pSampledImage =
1972                        bit_cast<const VkDescriptorImageInfo*>(
1973                            ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(
1974                                ToGuestAddr(new_value))->data.uniоn.pSampledImage)}
1975#endif
1976          : VkDescriptorType(
1977                ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))->type) ==
1978                      BERBERIS_VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ||
1979                  VkDescriptorType(
1980                      ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))
1981                          ->type) == BERBERIS_VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV
1982              ? VkDescriptorDataEXT{.accelerationStructure = VkDeviceAddress(
1983                                        ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(
1984                                            ToGuestAddr(new_value))
1985                                            ->data.uniоn.accelerationStructure)}
1986              : VkDescriptorDataEXT{
1987                    .pUniformBuffer = ToHostType(
1988                        ToHostAddr<GuestType<VkDescriptorGetInfoEXT>>(ToGuestAddr(new_value))
1989                            ->data.uniоn.pUniformBuffer,
1990                        holder.VkDescriptorAddressInfoEXT_holder_,
1991                        out_of_memory)}};
1992  return &holder.data_;
1993}
1994
1995`)
1996				}
1997			} else {
1998				holder := ""
1999				if extensible_type {
2000					holder = "std::unique_ptr<HostHolderBase> extensions_;\n  "
2001				}
2002				holder += name + " data_;"
2003				extra_holder_argument := ""
2004				if name == "VkCommandBufferBeginInfo" {
2005					extra_holder_argument = "[[maybe_unused]] bool has_inheritance_info, "
2006				}
2007				if isInputCompatible(typе, host_arch, guest_arch) {
2008					_, err = fmt.Fprintf(w, `  friend const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostHolder& holder, %[2]sbool& out_of_memory);
2009
2010 private:
2011};
2012
2013inline const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostHolder&, bool&) {
2014  return ToHostAddr<const %[1]s>(ToGuestAddr(new_value));
2015}
2016
2017`,
2018						name,
2019						extra_holder_argument)
2020				} else {
2021					_, err = fmt.Fprintf(w, `  friend const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostHolder& holder, %[4]sbool& out_of_memory);
2022
2023 private:
2024  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2025  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2026  %[2]s
2027};
2028
2029inline const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostHolder& holder, %[4]s[[maybe_unused]] bool& out_of_memory) {
2030  if (ToGuestAddr(new_value) == kNullGuestAddr) {
2031    return nullptr;
2032  }
2033  holder.data_ = {
2034      %[3]s };
2035  return &holder.data_;
2036}
2037
2038`,
2039						name,
2040						strings.Join(append(
2041							makeHolderList("GuestType<%s>::Host%sHolder %s_holder_;", true, typе, host_arch, guest_arch),
2042							holder), "\n  "),
2043						strings.Join(makeHostInitializerList(initializeConstStruct, name, typе, host_arch, guest_arch), "\n      "),
2044						extra_holder_argument)
2045				}
2046			}
2047			if err != nil {
2048				return err
2049			}
2050		}
2051	}
2052
2053	if conversion[name].need_const_array_convertor {
2054		if name == "VkAccelerationStructureGeometryKHR" {
2055			if isInputCompatible(typе, host_arch, guest_arch) {
2056				_, err = fmt.Fprintf(w, `class GuestType<const VkAccelerationStructureGeometryKHR*>::GuestArrayHolder {
2057 public:
2058  ~GuestArrayHolder();
2059  friend GuestType<const VkAccelerationStructureGeometryKHR*>;
2060
2061 private:
2062};
2063
2064inline GuestType<const VkAccelerationStructureGeometryKHR*>::GuestArrayHolder::~GuestArrayHolder() {
2065}
2066
2067inline GuestType<const VkAccelerationStructureGeometryKHR*>::GuestType(
2068    const VkAccelerationStructureGeometryKHR* const new_value,
2069    const VkAccelerationStructureGeometryKHR* const* const,
2070    GuestType<const VkAccelerationStructureGeometryKHR*>::GuestArrayHolder&,
2071    std::size_t,
2072    bool&)
2073    : value_(bit_cast<GuestAddr>(new_value)) {
2074}
2075
2076class GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder {
2077 public:
2078  ~HostArrayHolder();
2079  friend const VkAccelerationStructureGeometryKHR* ToHostType(
2080      const GuestType<const VkAccelerationStructureGeometryKHR*>& new_value,
2081      GuestType<const VkAccelerationStructureGeometryKHR* const*> const new_value_ptr,
2082      GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder& holder,
2083      std::size_t size,
2084      bool& out_of_memory);
2085
2086 private:
2087};
2088
2089inline GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder::~HostArrayHolder() {
2090}
2091
2092inline const VkAccelerationStructureGeometryKHR* ToHostType(
2093    const GuestType<const VkAccelerationStructureGeometryKHR*>& new_value,
2094    GuestType<const VkAccelerationStructureGeometryKHR* const*> const,
2095    GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder&,
2096    std::size_t,
2097    bool&) {
2098  return ToHostAddr<const VkAccelerationStructureGeometryKHR>(ToGuestAddr(new_value));
2099}
2100
2101`)
2102			} else {
2103				_, err = fmt.Fprintf(w, `class GuestType<const VkAccelerationStructureGeometryKHR*>::GuestArrayHolder {
2104 public:
2105  ~GuestArrayHolder();
2106  friend GuestType<const VkAccelerationStructureGeometryKHR*>;
2107
2108 private:
2109  friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2110  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2111  std::size_t size_ = 0;
2112  const VkAccelerationStructureGeometryKHR* origin_ = nullptr;
2113  std::unique_ptr<GuestHolderBase> extensions_;
2114  GuestType<const VkAccelerationStructureGeometryKHR>* data_ = nullptr;
2115};
2116
2117inline GuestType<const VkAccelerationStructureGeometryKHR*>::GuestArrayHolder::~GuestArrayHolder() {
2118  delete[] data_;
2119}
2120
2121inline GuestType<const VkAccelerationStructureGeometryKHR*>::GuestType(
2122    const VkAccelerationStructureGeometryKHR* const new_value,
2123    const VkAccelerationStructureGeometryKHR* const* const new_value_ptr,
2124    GuestType<const VkAccelerationStructureGeometryKHR*>::GuestArrayHolder& holder,
2125    std::size_t size,
2126    [[maybe_unused]] bool& out_of_memory)
2127    : value_((new_value == nullptr && new_value_ptr == nullptr)
2128                 ? kNullGuestAddr
2129                 : ToGuestAddr(holder.data_ = new (std::nothrow)
2130                                   GuestType<const VkAccelerationStructureGeometryKHR>[size])) {
2131  if ((new_value != nullptr || new_value_ptr != nullptr) && value_ == kNullGuestAddr) {
2132    out_of_memory = true;
2133    return;
2134  }
2135  holder.size_ = size;
2136  holder.origin_ = new_value;
2137  if (new_value != nullptr) {
2138    for (std::size_t index = 0; index < size; ++index) {
2139      ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>>(value_)[index] = {
2140          .sType = GuestType<VkStructureType>(new_value[index].sType),
2141          .pNext = ConvertOptionalStructures(new_value[index].pNext, holder.extensions_, out_of_memory),
2142          .geometryType = GuestType<VkGeometryTypeKHR>(new_value[index].geometryType),
2143          .flags = GuestType<VkGeometryFlagsKHR>(new_value[index].flags)};
2144    }
2145  } else {
2146    for (std::size_t index = 0; index < size; ++index) {
2147      ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>>(value_)[index] = {
2148          .sType = GuestType<VkStructureType>(new_value_ptr[index]->sType),
2149          .pNext = ConvertOptionalStructures(new_value_ptr[index]->pNext, holder.extensions_, out_of_memory),
2150          .geometryType = GuestType<VkGeometryTypeKHR>(new_value_ptr[index]->geometryType),
2151          .flags = GuestType<VkGeometryFlagsKHR>(new_value_ptr[index]->flags)};
2152    }
2153  }
2154}
2155
2156class GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder {
2157 public:
2158  ~HostArrayHolder();
2159  friend const VkAccelerationStructureGeometryKHR* ToHostType(
2160      const GuestType<const VkAccelerationStructureGeometryKHR*>& new_value,
2161      GuestType<const VkAccelerationStructureGeometryKHR* const*> const new_value_ptr,
2162      GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder& holder,
2163      std::size_t size,
2164      bool& out_of_memory);
2165
2166 private:
2167  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2168  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2169  std::size_t size_ = 0;
2170  std::unique_ptr<GuestHolderBase> extensions_;
2171  VkAccelerationStructureGeometryKHR* data_ = nullptr;
2172};
2173
2174inline GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder::~HostArrayHolder() {
2175  delete[] data_;
2176}
2177
2178inline const VkAccelerationStructureGeometryKHR* ToHostType(
2179    const GuestType<const VkAccelerationStructureGeometryKHR*>& new_value,
2180    GuestType<const VkAccelerationStructureGeometryKHR* const*> const new_value_ptr,
2181    GuestType<const VkAccelerationStructureGeometryKHR*>::HostArrayHolder& holder,
2182    std::size_t size,
2183    bool& out_of_memory) {
2184  if (ToGuestAddr(new_value) == kNullGuestAddr && ToGuestAddr(new_value_ptr) == kNullGuestAddr) {
2185    return nullptr;
2186  }
2187  if ((holder.data_ = new (std::nothrow) VkAccelerationStructureGeometryKHR[size]) == nullptr) {
2188    out_of_memory = true;
2189    return nullptr;
2190  }
2191  holder.size_ = size;
2192  if (ToGuestAddr(new_value) != 0) {
2193    for (std::size_t index = 0; index < size; ++index) {
2194      holder.data_[index] = {
2195          .sType = VkStructureType(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>>(
2196                                       ToGuestAddr(new_value))[index]
2197                                       .sType),
2198          .pNext = ConvertOptionalStructures(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>>(
2199                                                 ToGuestAddr(new_value))[index]
2200                                                 .pNext,
2201                                                 holder.extensions_,
2202                                                 out_of_memory),
2203          .geometryType =
2204              VkGeometryTypeKHR(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>>(
2205                                    ToGuestAddr(new_value))[index]
2206                                    .geometryType),
2207          .flags = VkGeometryFlagsKHR(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>>(
2208                                          ToGuestAddr(new_value))[index]
2209                                          .flags)};
2210    }
2211  } else {
2212    for (std::size_t index = 0; index < size; ++index) {
2213      holder.data_[index] = {
2214          .sType = VkStructureType(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>*>(
2215                                       ToGuestAddr(new_value_ptr))[index]
2216                                       ->sType),
2217          .pNext = ConvertOptionalStructures(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>*>(
2218                                                 ToGuestAddr(new_value))[index]
2219                                                 ->pNext,
2220                                                 holder.extensions_,
2221                                                 out_of_memory),
2222          .geometryType =
2223              VkGeometryTypeKHR(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>*>(
2224                                    ToGuestAddr(new_value))[index]
2225                                    ->geometryType),
2226          .flags = VkGeometryFlagsKHR(ToHostAddr<GuestType<VkAccelerationStructureGeometryKHR>*>(
2227                                          ToGuestAddr(new_value))[index]
2228                                          ->flags)};
2229    }
2230  }
2231  return holder.data_;
2232}
2233
2234`)
2235			}
2236			if err != nil {
2237				return err
2238			}
2239		} else if name == "VkAccelerationStructureBuildGeometryInfoKHR" {
2240			if isInputCompatible(typе, host_arch, guest_arch) {
2241				_, err = fmt.Fprintf(w, `class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestArrayHolder {
2242 public:
2243  ~GuestArrayHolder();
2244  friend GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>;
2245
2246 private:
2247};
2248
2249inline GuestType<
2250    const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestArrayHolder::~GuestArrayHolder() {
2251}
2252
2253inline GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestType(
2254    const VkAccelerationStructureBuildGeometryInfoKHR* const new_value,
2255    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestArrayHolder&,
2256    std::size_t,
2257    bool&)
2258    : value_(bit_cast<GuestAddr>(new_value)) {
2259}
2260
2261class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder {
2262 public:
2263  ~HostArrayHolder();
2264  friend const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
2265      const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
2266      GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder& holder,
2267      std::size_t size,
2268      bool& out_of_memory);
2269
2270 private:
2271};
2272
2273inline GuestType<
2274    const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder::~HostArrayHolder() {
2275}
2276
2277inline const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
2278    const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
2279    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder&,
2280    std::size_t,
2281    bool&) {
2282  return ToHostAddr<VkAccelerationStructureBuildGeometryInfoKHR>(ToGuestAddr(new_value));
2283}
2284
2285`)
2286			} else {
2287				_, err = fmt.Fprintf(w, `class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestArrayHolder {
2288 public:
2289  ~GuestArrayHolder();
2290  friend GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>;
2291
2292 private:
2293 friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2294  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2295  std::size_t size_ = 0;
2296  std::unique_ptr<GuestHolderBase> extensions_;
2297  GuestType<const VkAccelerationStructureBuildGeometryInfoKHR>* data_ = nullptr;
2298  GuestType<const struct VkAccelerationStructureGeometryKHR*>::GuestArrayHolder*
2299      pGeometries_holder_ = nullptr;
2300};
2301
2302inline GuestType<
2303    const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestArrayHolder::~GuestArrayHolder() {
2304  delete[] pGeometries_holder_;
2305  delete[] data_;
2306}
2307
2308inline GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestType(
2309    const VkAccelerationStructureBuildGeometryInfoKHR* const new_value,
2310    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::GuestArrayHolder& holder,
2311    std::size_t size,
2312    [[maybe_unused]] bool& out_of_memory)
2313    : value_(new_value == nullptr
2314                 ? kNullGuestAddr
2315                 : ToGuestAddr(
2316                       holder.data_ = new (std::nothrow)
2317                           GuestType<const VkAccelerationStructureBuildGeometryInfoKHR>[size])) {
2318  if (new_value == nullptr) {
2319    holder.pGeometries_holder_ = new (std::nothrow)
2320        GuestType<const struct VkAccelerationStructureGeometryKHR*>::GuestArrayHolder[size];
2321  }
2322  if (new_value != nullptr && (value_ == kNullGuestAddr || holder.pGeometries_holder_ == nullptr)) {
2323    out_of_memory = true;
2324    return;
2325  }
2326  holder.size_ = size;
2327  for (std::size_t index = 0; index < size; ++index) {
2328    ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(value_)[index] = {
2329        .sType = GuestType<VkStructureType>(new_value[index].sType),
2330        .pNext = ConvertOptionalStructures(new_value[index].pNext, holder.extensions_, out_of_memory),
2331        .type = GuestType<VkAccelerationStructureTypeKHR>(new_value[index].type),
2332        .flags = GuestType<VkBuildAccelerationStructureFlagsKHR>(new_value[index].flags),
2333        .mode = GuestType<VkBuildAccelerationStructureModeKHR>(new_value[index].mode),
2334        .srcAccelerationStructure =
2335            GuestType<VkAccelerationStructureKHR>(new_value[index].srcAccelerationStructure),
2336        .dstAccelerationStructure =
2337            GuestType<VkAccelerationStructureKHR>(new_value[index].dstAccelerationStructure),
2338        .geometryCount = GuestType<std::uint32_t>(new_value[index].geometryCount),
2339        .pGeometries = GuestType<const struct VkAccelerationStructureGeometryKHR*>(
2340            new_value[index].pGeometries,
2341            new_value[index].ppGeometries,
2342            holder.pGeometries_holder_[index],
2343            new_value[index].geometryCount,
2344            out_of_memory),
2345        .ppGeometries =
2346            GuestType<const struct VkAccelerationStructureGeometryKHR* const*>(nullptr)};
2347  }
2348}
2349
2350class GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder {
2351 public:
2352  ~HostArrayHolder();
2353  friend const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
2354      const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
2355      GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder& holder,
2356      std::size_t size,
2357      bool& out_of_memory);
2358
2359 private:
2360  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2361  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2362  std::size_t size_ = 0;
2363  std::unique_ptr<HostHolderBase> extensions_;
2364  GuestType<const VkAccelerationStructureBuildGeometryInfoKHR>* origin_ = nullptr;
2365  VkAccelerationStructureBuildGeometryInfoKHR* data_ = nullptr;
2366  GuestType<const struct VkAccelerationStructureGeometryKHR*>::HostArrayHolder pGeometries_holder_;
2367};
2368
2369inline GuestType<
2370    const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder::~HostArrayHolder() {
2371  delete[] data_;
2372}
2373
2374inline const VkAccelerationStructureBuildGeometryInfoKHR* ToHostType(
2375    const GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>& new_value,
2376    GuestType<const VkAccelerationStructureBuildGeometryInfoKHR*>::HostArrayHolder& holder,
2377    std::size_t size,
2378    bool& out_of_memory) {
2379  if (ToGuestAddr(new_value) == kNullGuestAddr) {
2380    return nullptr;
2381  }
2382  if ((holder.data_ = new (std::nothrow) VkAccelerationStructureBuildGeometryInfoKHR[size]) ==
2383      nullptr) {
2384    out_of_memory = true;
2385    return nullptr;
2386  }
2387  holder.size_ = size;
2388  holder.origin_ = ToHostAddr<GuestType<const VkAccelerationStructureBuildGeometryInfoKHR>>(
2389      ToGuestAddr(new_value));
2390  for (std::size_t index = 0; index < size; ++index) {
2391    holder.data_[index] = {
2392        .sType = VkStructureType(ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2393                                     ToGuestAddr(new_value))[index]
2394                                     .sType),
2395        .pNext = ConvertOptionalStructures(ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2396                                              ToGuestAddr(new_value))[index]
2397                                              .pNext,
2398                                              holder.extensions_,
2399                                              out_of_memory),
2400        .type = VkAccelerationStructureTypeKHR(
2401            ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2402                ToGuestAddr(new_value))[index]
2403                .type),
2404        .flags = VkBuildAccelerationStructureFlagsKHR(
2405            ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2406                ToGuestAddr(new_value))[index]
2407                .flags),
2408        .mode = VkBuildAccelerationStructureModeKHR(
2409            ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2410                ToGuestAddr(new_value))[index]
2411                .mode),
2412        .srcAccelerationStructure = VkAccelerationStructureKHR(
2413            ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2414                ToGuestAddr(new_value))[index]
2415                .srcAccelerationStructure),
2416        .dstAccelerationStructure = VkAccelerationStructureKHR(
2417            ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2418                ToGuestAddr(new_value))[index]
2419                .dstAccelerationStructure),
2420        .geometryCount =
2421            std::uint32_t(ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2422                              ToGuestAddr(new_value))[index]
2423                              .geometryCount),
2424        .pGeometries =
2425            ToHostType(ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2426                           ToGuestAddr(new_value))[index]
2427                           .pGeometries,
2428                       ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2429                           ToGuestAddr(new_value))[index]
2430                           .ppGeometries,
2431                       holder.pGeometries_holder_,
2432                       ToHostAddr<GuestType<VkAccelerationStructureBuildGeometryInfoKHR>>(
2433                           ToGuestAddr(new_value))[index]
2434                           .geometryCount,
2435                       out_of_memory),
2436        .ppGeometries = nullptr};
2437  }
2438  return holder.data_;
2439}
2440
2441`)
2442			}
2443			if err != nil {
2444				return err
2445			}
2446		} else if name == "VkGraphicsPipelineCreateInfo" {
2447			// Some fields can be invalid depending on whether rasterization is enabled.
2448			// We cannot touch/convert them automatically. Thus manual implementation.
2449			// All modifications compared to autogenerated version are marked with MOD START/END.
2450			_, err = fmt.Fprintf(w, `class GuestType<const VkGraphicsPipelineCreateInfo*>::GuestArrayHolder {
2451 public:
2452  ~GuestArrayHolder();
2453  friend GuestType<const VkGraphicsPipelineCreateInfo*>;
2454
2455 private:
2456  friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2457  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2458  std::size_t size_ = 0;
2459  std::unique_ptr<GuestHolderBase> extensions_;
2460  GuestType<const VkGraphicsPipelineCreateInfo>* data_ = nullptr;
2461  GuestType<const struct VkPipelineShaderStageCreateInfo *>::GuestArrayHolder* pStages_holder_ = nullptr;
2462  GuestType<const struct VkPipelineVertexInputStateCreateInfo *>::GuestHolder* pVertexInputState_holder_ = nullptr;
2463  GuestType<const struct VkPipelineInputAssemblyStateCreateInfo *>::GuestHolder* pInputAssemblyState_holder_ = nullptr;
2464  GuestType<const struct VkPipelineTessellationStateCreateInfo *>::GuestHolder* pTessellationState_holder_ = nullptr;
2465  GuestType<const struct VkPipelineViewportStateCreateInfo *>::GuestHolder* pViewportState_holder_ = nullptr;
2466  GuestType<const struct VkPipelineRasterizationStateCreateInfo *>::GuestHolder* pRasterizationState_holder_ = nullptr;
2467  GuestType<const struct VkPipelineMultisampleStateCreateInfo *>::GuestHolder* pMultisampleState_holder_ = nullptr;
2468  GuestType<const struct VkPipelineDepthStencilStateCreateInfo *>::GuestHolder* pDepthStencilState_holder_ = nullptr;
2469  GuestType<const struct VkPipelineColorBlendStateCreateInfo *>::GuestHolder* pColorBlendState_holder_ = nullptr;
2470  GuestType<const struct VkPipelineDynamicStateCreateInfo *>::GuestHolder* pDynamicState_holder_ = nullptr;
2471};
2472
2473inline GuestType<const VkGraphicsPipelineCreateInfo*>::GuestArrayHolder::~GuestArrayHolder() {
2474  delete[] data_;
2475  delete[] pStages_holder_;
2476  delete[] pVertexInputState_holder_;
2477  delete[] pInputAssemblyState_holder_;
2478  delete[] pTessellationState_holder_;
2479  delete[] pViewportState_holder_;
2480  delete[] pRasterizationState_holder_;
2481  delete[] pMultisampleState_holder_;
2482  delete[] pDepthStencilState_holder_;
2483  delete[] pColorBlendState_holder_;
2484  delete[] pDynamicState_holder_;
2485}
2486
2487inline GuestType<const VkGraphicsPipelineCreateInfo*>::GuestType(const VkGraphicsPipelineCreateInfo* const new_value, GuestType<const VkGraphicsPipelineCreateInfo*>::GuestArrayHolder& holder, std::size_t size, [[maybe_unused]] bool& out_of_memory) : value_(new_value == nullptr ? kNullGuestAddr : ToGuestAddr(holder.data_ = new (std::nothrow) GuestType<const VkGraphicsPipelineCreateInfo>[size])) {
2488  if (new_value != nullptr && value_ == kNullGuestAddr) {
2489    out_of_memory = true;
2490    return;
2491  }
2492  holder.size_ = size;
2493  if ((holder.pStages_holder_ = new (std::nothrow) GuestType<const struct VkPipelineShaderStageCreateInfo *>::GuestArrayHolder[size]) == nullptr) {
2494    out_of_memory = true;
2495    return;
2496  };
2497  if ((holder.pVertexInputState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineVertexInputStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2498    out_of_memory = true;
2499    return;
2500  };
2501  if ((holder.pInputAssemblyState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineInputAssemblyStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2502    out_of_memory = true;
2503    return;
2504  };
2505  if ((holder.pTessellationState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineTessellationStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2506    out_of_memory = true;
2507    return;
2508  };
2509  if ((holder.pViewportState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineViewportStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2510    out_of_memory = true;
2511    return;
2512  };
2513  if ((holder.pRasterizationState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineRasterizationStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2514    out_of_memory = true;
2515    return;
2516  };
2517  if ((holder.pMultisampleState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineMultisampleStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2518    out_of_memory = true;
2519    return;
2520  };
2521  if ((holder.pDepthStencilState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineDepthStencilStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2522    out_of_memory = true;
2523    return;
2524  };
2525  if ((holder.pColorBlendState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineColorBlendStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2526    out_of_memory = true;
2527    return;
2528  };
2529  if ((holder.pDynamicState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineDynamicStateCreateInfo *>::GuestHolder[size]) == nullptr) {
2530    out_of_memory = true;
2531    return;
2532  };
2533  for (std::size_t index = 0; index < size; ++index) {
2534    // MOD START
2535    auto* host_rasterization_state = new_value[index].pRasterizationState;
2536    bool rasterization_enabled = host_rasterization_state->rasterizerDiscardEnable == BERBERIS_VK_FALSE ||
2537                              // When dynamic state presents the rasterization may be enabled later.
2538                              new_value[index].pDynamicState;
2539    // MOD END
2540    ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(value_)[index] = {
2541      .sType = GuestType<VkStructureType>(new_value[index].sType),
2542        .pNext = ConvertOptionalStructures(new_value[index].pNext, holder.extensions_, out_of_memory),
2543        .flags = GuestType<VkPipelineCreateFlags>(new_value[index].flags),
2544        .stageCount = GuestType<std::uint32_t>(new_value[index].stageCount),
2545        .pStages = GuestType<const struct VkPipelineShaderStageCreateInfo *>(new_value[index].pStages, holder.pStages_holder_[index], new_value[index].stageCount, out_of_memory),
2546        .pVertexInputState = GuestType<const struct VkPipelineVertexInputStateCreateInfo *>(new_value[index].pVertexInputState, holder.pVertexInputState_holder_[index], out_of_memory),
2547        .pInputAssemblyState = GuestType<const struct VkPipelineInputAssemblyStateCreateInfo *>(new_value[index].pInputAssemblyState, holder.pInputAssemblyState_holder_[index], out_of_memory),
2548        .pTessellationState = GuestType<const struct VkPipelineTessellationStateCreateInfo *>(new_value[index].pTessellationState, holder.pTessellationState_holder_[index], out_of_memory),
2549        // MOD START
2550        .pViewportState = rasterization_enabled ? GuestType<const struct VkPipelineViewportStateCreateInfo *>(new_value[index].pViewportState, holder.pViewportState_holder_[index], out_of_memory) : GuestType<const struct VkPipelineViewportStateCreateInfo *>(),
2551        .pRasterizationState = GuestType<const struct VkPipelineRasterizationStateCreateInfo *>(new_value[index].pRasterizationState, holder.pRasterizationState_holder_[index], out_of_memory),
2552        .pMultisampleState = rasterization_enabled ? GuestType<const struct VkPipelineMultisampleStateCreateInfo *>(new_value[index].pMultisampleState, holder.pMultisampleState_holder_[index], out_of_memory) : GuestType<const struct VkPipelineMultisampleStateCreateInfo *>(),
2553        .pDepthStencilState = rasterization_enabled ? GuestType<const struct VkPipelineDepthStencilStateCreateInfo *>(new_value[index].pDepthStencilState, holder.pDepthStencilState_holder_[index], out_of_memory) : GuestType<const struct VkPipelineDepthStencilStateCreateInfo *>(),
2554        .pColorBlendState = rasterization_enabled ? GuestType<const struct VkPipelineColorBlendStateCreateInfo *>(new_value[index].pColorBlendState, holder.pColorBlendState_holder_[index], out_of_memory) : GuestType<const struct VkPipelineColorBlendStateCreateInfo *>(),
2555        // MOD END
2556        .pDynamicState = GuestType<const struct VkPipelineDynamicStateCreateInfo *>(new_value[index].pDynamicState, holder.pDynamicState_holder_[index], out_of_memory),
2557        .layout = GuestType<VkPipelineLayout>(new_value[index].layout),
2558        .renderPass = GuestType<VkRenderPass>(new_value[index].renderPass),
2559        .subpass = GuestType<std::uint32_t>(new_value[index].subpass),
2560        .basePipelineHandle = GuestType<VkPipeline>(new_value[index].basePipelineHandle),
2561        .basePipelineIndex = GuestType<std::int32_t>(new_value[index].basePipelineIndex) };
2562  }
2563}
2564
2565class GuestType<const VkGraphicsPipelineCreateInfo*>::HostArrayHolder {
2566 public:
2567  ~HostArrayHolder();
2568  friend const VkGraphicsPipelineCreateInfo* ToHostType(const GuestType<const VkGraphicsPipelineCreateInfo*>& new_value, GuestType<const VkGraphicsPipelineCreateInfo*>::HostArrayHolder& holder, std::size_t size, bool& out_of_memory);
2569
2570 private:
2571  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2572  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2573  std::size_t size_ = 0;
2574  std::unique_ptr<HostHolderBase> extensions_;
2575  VkGraphicsPipelineCreateInfo* data_ = nullptr;
2576  GuestType<const struct VkPipelineShaderStageCreateInfo *>::HostArrayHolder* pStages_holder_ = nullptr;
2577  GuestType<const struct VkPipelineVertexInputStateCreateInfo *>::HostHolder* pVertexInputState_holder_ = nullptr;
2578  GuestType<const struct VkPipelineInputAssemblyStateCreateInfo *>::HostHolder* pInputAssemblyState_holder_ = nullptr;
2579  GuestType<const struct VkPipelineTessellationStateCreateInfo *>::HostHolder* pTessellationState_holder_ = nullptr;
2580  GuestType<const struct VkPipelineViewportStateCreateInfo *>::HostHolder* pViewportState_holder_ = nullptr;
2581  GuestType<const struct VkPipelineRasterizationStateCreateInfo *>::HostHolder* pRasterizationState_holder_ = nullptr;
2582  GuestType<const struct VkPipelineMultisampleStateCreateInfo *>::HostHolder* pMultisampleState_holder_ = nullptr;
2583  GuestType<const struct VkPipelineDepthStencilStateCreateInfo *>::HostHolder* pDepthStencilState_holder_ = nullptr;
2584  GuestType<const struct VkPipelineColorBlendStateCreateInfo *>::HostHolder* pColorBlendState_holder_ = nullptr;
2585  GuestType<const struct VkPipelineDynamicStateCreateInfo *>::HostHolder* pDynamicState_holder_ = nullptr;
2586};
2587
2588inline GuestType<const VkGraphicsPipelineCreateInfo*>::HostArrayHolder::~HostArrayHolder() {
2589  delete[] data_;
2590  delete[] pStages_holder_;
2591  delete[] pVertexInputState_holder_;
2592  delete[] pInputAssemblyState_holder_;
2593  delete[] pTessellationState_holder_;
2594  delete[] pViewportState_holder_;
2595  delete[] pRasterizationState_holder_;
2596  delete[] pMultisampleState_holder_;
2597  delete[] pDepthStencilState_holder_;
2598  delete[] pColorBlendState_holder_;
2599  delete[] pDynamicState_holder_;
2600}
2601
2602inline const VkGraphicsPipelineCreateInfo* ToHostType(const GuestType<const VkGraphicsPipelineCreateInfo*>& new_value, GuestType<const VkGraphicsPipelineCreateInfo*>::HostArrayHolder& holder, std::size_t size, bool& out_of_memory) {
2603  if (ToGuestAddr(new_value) == kNullGuestAddr) {
2604    return nullptr;
2605  }
2606  if ((holder.data_ = new (std::nothrow) VkGraphicsPipelineCreateInfo[size]) == nullptr) {
2607    out_of_memory = true;
2608    return nullptr;
2609  }
2610  if ((holder.pStages_holder_ = new (std::nothrow) GuestType<const struct VkPipelineShaderStageCreateInfo *>::HostArrayHolder[size]) == nullptr) {
2611    out_of_memory = true;
2612    return nullptr;
2613  };
2614  if ((holder.pVertexInputState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineVertexInputStateCreateInfo *>::HostHolder[size]) == nullptr) {
2615    out_of_memory = true;
2616    return nullptr;
2617  };
2618  if ((holder.pInputAssemblyState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineInputAssemblyStateCreateInfo *>::HostHolder[size]) == nullptr) {
2619    out_of_memory = true;
2620    return nullptr;
2621  };
2622  if ((holder.pTessellationState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineTessellationStateCreateInfo *>::HostHolder[size]) == nullptr) {
2623    out_of_memory = true;
2624    return nullptr;
2625  };
2626  if ((holder.pViewportState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineViewportStateCreateInfo *>::HostHolder[size]) == nullptr) {
2627    out_of_memory = true;
2628    return nullptr;
2629  };
2630  if ((holder.pRasterizationState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineRasterizationStateCreateInfo *>::HostHolder[size]) == nullptr) {
2631    out_of_memory = true;
2632    return nullptr;
2633  };
2634  if ((holder.pMultisampleState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineMultisampleStateCreateInfo *>::HostHolder[size]) == nullptr) {
2635    out_of_memory = true;
2636    return nullptr;
2637  };
2638  if ((holder.pDepthStencilState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineDepthStencilStateCreateInfo *>::HostHolder[size]) == nullptr) {
2639    out_of_memory = true;
2640    return nullptr;
2641  };
2642  if ((holder.pColorBlendState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineColorBlendStateCreateInfo *>::HostHolder[size]) == nullptr) {
2643    out_of_memory = true;
2644    return nullptr;
2645  };
2646  if ((holder.pDynamicState_holder_ = new (std::nothrow) GuestType<const struct VkPipelineDynamicStateCreateInfo *>::HostHolder[size]) == nullptr) {
2647    out_of_memory = true;
2648    return nullptr;
2649  };
2650  holder.size_ = size;
2651  for (std::size_t index = 0; index < size; ++index) {
2652    // MOD START
2653    auto& pipeline_info = ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index];
2654    auto guest_rasterization_state = pipeline_info.pRasterizationState;
2655    bool rasterization_enabled = ToHostAddr<GuestType<VkPipelineRasterizationStateCreateInfo>>(ToGuestAddr(guest_rasterization_state))->rasterizerDiscardEnable == BERBERIS_VK_FALSE
2656                              // When dynamic state presents the rasterization may be enabled later.
2657                              || ToGuestAddr(pipeline_info.pDynamicState) != kNullGuestAddr;
2658    // MOD END
2659    holder.data_[index] = {
2660      .sType = VkStructureType(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].sType),
2661      .pNext = ConvertOptionalStructures(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].pNext, holder.extensions_, out_of_memory),
2662      .flags = VkPipelineCreateFlags(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].flags),
2663      .stageCount = std::uint32_t(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].stageCount),
2664      .pStages = ToHostType(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].pStages, holder.pStages_holder_[index], ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].stageCount, out_of_memory),
2665      .pVertexInputState = ToHostType(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].pVertexInputState, holder.pVertexInputState_holder_[index], out_of_memory),
2666      .pInputAssemblyState = ToHostType(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].pInputAssemblyState, holder.pInputAssemblyState_holder_[index], out_of_memory),
2667      .pTessellationState = ToHostType(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].pTessellationState, holder.pTessellationState_holder_[index], out_of_memory),
2668      // MOD START
2669      .pViewportState = rasterization_enabled ? ToHostType(pipeline_info.pViewportState, holder.pViewportState_holder_[index], out_of_memory) : nullptr,
2670      .pRasterizationState = ToHostType(pipeline_info.pRasterizationState, holder.pRasterizationState_holder_[index], out_of_memory),
2671      .pMultisampleState = rasterization_enabled ? ToHostType(pipeline_info.pMultisampleState, holder.pMultisampleState_holder_[index], out_of_memory) :
2672      nullptr,
2673      .pDepthStencilState = rasterization_enabled ? ToHostType(pipeline_info.pDepthStencilState, holder.pDepthStencilState_holder_[index], out_of_memory) : nullptr,
2674      .pColorBlendState = rasterization_enabled ? ToHostType(pipeline_info.pColorBlendState, holder.pColorBlendState_holder_[index], out_of_memory) : nullptr,
2675      // MOD END
2676      .pDynamicState = ToHostType(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].pDynamicState, holder.pDynamicState_holder_[index], out_of_memory),
2677      .layout = VkPipelineLayout(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].layout),
2678      .renderPass = VkRenderPass(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].renderPass),
2679      .subpass = std::uint32_t(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].subpass),
2680      .basePipelineHandle = VkPipeline(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].basePipelineHandle),
2681      .basePipelineIndex = std::int32_t(ToHostAddr<GuestType<VkGraphicsPipelineCreateInfo>>(ToGuestAddr(new_value))[index].basePipelineIndex) };
2682  }
2683  return holder.data_;
2684}
2685
2686`)
2687			if err != nil {
2688				return err
2689			}
2690		} else {
2691			holder := ""
2692			if extensible_type {
2693				holder = "std::unique_ptr<GuestHolderBase> extensions_;\n  "
2694			}
2695			holder += "GuestType<const " + name + ">* data_ = nullptr;"
2696			if isInputCompatible(typе, host_arch, guest_arch) {
2697				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::GuestArrayHolder {
2698 public:
2699  ~GuestArrayHolder();
2700  friend GuestType<const %[1]s*>;
2701
2702 private:
2703};
2704
2705inline GuestType<const %[1]s*>::GuestArrayHolder::~GuestArrayHolder() {
2706}
2707
2708inline GuestType<const %[1]s*>::GuestType(const %[1]s* const new_value, GuestType<const %[1]s*>::GuestArrayHolder&, std::size_t, bool&) : value_(bit_cast<GuestAddr>(new_value)) {
2709}
2710
2711`,
2712					name)
2713			} else {
2714				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::GuestArrayHolder {
2715 public:
2716  ~GuestArrayHolder();
2717  friend GuestType<const %[1]s*>;
2718
2719 private:
2720  friend GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2721  friend GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory);
2722  std::size_t size_ = 0;
2723  %[2]s
2724};
2725
2726inline GuestType<const %[1]s*>::GuestArrayHolder::~GuestArrayHolder() {
2727  %[3]s
2728}
2729
2730// Apparently "size == 0" is used for pointers marked as noautovalidity="true" in vk.xml and "new_value == nullptr" is used for pointers marked with optional="true", but it's not clear how consistent is it.
2731//
2732// Better to check both options in all cases, it's not too slow in practice.
2733//
2734inline GuestType<const %[1]s*>::GuestType(const %[1]s* const new_value, GuestType<const %[1]s*>::GuestArrayHolder& holder, std::size_t size, [[maybe_unused]] bool& out_of_memory) : value_((size == 0 || new_value == nullptr) ? kNullGuestAddr : ToGuestAddr(holder.data_ = new (std::nothrow) GuestType<const %[1]s>[size])) {
2735  %[4]s
2736  for (std::size_t index = 0; index < size; ++index) {
2737    ToHostAddr<GuestType<%[1]s>>(value_)[index] = {
2738      %[5]s };
2739  }
2740}
2741
2742`,
2743					name,
2744					strings.Join(append([]string{holder},
2745						makeHolderList("GuestType<%s>::Guest%sHolder* %s_holder_ = nullptr;", true, typе, host_arch, guest_arch)...), "\n  "),
2746					strings.Join(append([]string{"delete[] data_;"},
2747						makeHolderList("delete[] %[3]s_holder_;", true, typе, host_arch, guest_arch)...), "\n  "),
2748					strings.Join(append([]string{"if (value_ == kNullGuestAddr) {\n    if (size != 0 && new_value != nullptr) {\n      out_of_memory = true;\n    }\n    return;\n  }\n  holder.size_ = size;"},
2749						makeHolderList("if ((holder.%[3]s_holder_ = new (std::nothrow) GuestType<%[1]s>::Guest%[2]sHolder[size]) == nullptr) {\n    out_of_memory = true;\n    return;\n  };", true, typе, host_arch, guest_arch)...), "\n  "),
2750					strings.Join(makeGuestInitializerListForArray(initializeConstStruct, name, typе, host_arch, guest_arch), "\n        "))
2751			}
2752			if err != nil {
2753				return err
2754			}
2755
2756			holder = ""
2757			if extensible_type {
2758				holder = "std::unique_ptr<HostHolderBase> extensions_;\n  "
2759			}
2760			holder += name + "* data_ = nullptr;"
2761			if isInputCompatible(typе, host_arch, guest_arch) {
2762				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::HostArrayHolder {
2763 public:
2764  ~HostArrayHolder();
2765  friend const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostArrayHolder& holder, std::size_t size, bool& out_of_memory);
2766
2767 private:
2768};
2769
2770inline GuestType<const %[1]s*>::HostArrayHolder::~HostArrayHolder() {
2771}
2772
2773inline const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostArrayHolder&, std::size_t, bool&) {
2774  return ToHostAddr<const %[1]s>(ToGuestAddr(new_value));
2775}
2776
2777`,
2778					name)
2779			} else {
2780				_, err = fmt.Fprintf(w, `class GuestType<const %[1]s*>::HostArrayHolder {
2781 public:
2782  ~HostArrayHolder();
2783  friend const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostArrayHolder& holder, std::size_t size, bool& out_of_memory);
2784
2785 private:
2786  friend void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2787  friend const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory);
2788  std::size_t size_ = 0;
2789  %[2]s
2790};
2791
2792inline GuestType<const %[1]s*>::HostArrayHolder::~HostArrayHolder() {
2793  %[3]s
2794}
2795
2796inline const %[1]s* ToHostType(const GuestType<const %[1]s*>& new_value, GuestType<const %[1]s*>::HostArrayHolder& holder, std::size_t size, bool& out_of_memory) {
2797  %[4]s
2798  for (std::size_t index = 0; index < size; ++index) {
2799    holder.data_[index] = {
2800      %[5]s };
2801  }
2802  return holder.data_;
2803}
2804
2805`,
2806					name,
2807					strings.Join(append([]string{holder},
2808						makeHolderList("GuestType<%s>::Host%sHolder* %s_holder_ = nullptr;", true, typе, host_arch, guest_arch)...), "\n  "),
2809					strings.Join(append([]string{"delete[] data_;"},
2810						makeHolderList("delete[] %[3]s_holder_;", true, typе, host_arch, guest_arch)...), "\n  "),
2811					strings.Join(append([]string{"if (size == 0 || ToGuestAddr(new_value) == kNullGuestAddr) {\n    return nullptr;\n  }\n  holder.size_ = size;\n  if ((holder.data_ = new (std::nothrow) " + name + "[size]) == nullptr) {\n    out_of_memory = true;\n    return nullptr;\n  }"},
2812						makeHolderList("if ((holder.%[3]s_holder_ = new (std::nothrow) GuestType<%[1]s>::Host%[2]sHolder[size]) == nullptr) {\n    out_of_memory = true;\n    return nullptr;\n  };", true, typе, host_arch, guest_arch)...), "\n  "),
2813					strings.Join(makeHostInitializerListForArray(initializeConstStruct, name, typе, host_arch, guest_arch), "\n      "))
2814			}
2815			if err != nil {
2816				return err
2817			}
2818		}
2819	}
2820
2821	return nil
2822}
2823
2824func makeHolderList(format string, const_types bool, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) []string {
2825	holders := []string{}
2826	return fillHolderList(holders, format, const_types, typе, host_arch, guest_arch)
2827}
2828
2829func fillHolderList(holders []string, format string, const_types bool, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) []string {
2830	ids := typе.NumField(cpp_types.FirstArch)
2831	for id := uint(0); id < ids; id++ {
2832		field_name := typе.Field(id, cpp_types.FirstArch).Name()
2833		field_type := typе.Field(id, cpp_types.FirstArch).Type()
2834		if !doesNeedHolder(field_type, host_arch, guest_arch) || field_name == "pNext" {
2835			continue
2836		}
2837		switch field_type.Kind(cpp_types.FirstArch) {
2838		case cpp_types.Struct, cpp_types.Union:
2839			holders = fillHolderList(holders, format, const_types, field_type, host_arch, guest_arch)
2840		default:
2841			field_length := typе.Field(id, cpp_types.FirstArch).BaseFieldInfo().(vulkan_xml.ExtendedFieldInfo).Length()
2842			if field_length == nil {
2843				holders = append(holders, fmt.Sprintf(
2844					format,
2845					field_type.Name(host_arch),
2846					"",
2847					field_name))
2848			} else {
2849				holders = append(holders, fmt.Sprintf(
2850					format,
2851					field_type.Name(host_arch),
2852					"Array",
2853					field_name))
2854			}
2855		}
2856	}
2857	return holders
2858}
2859
2860// initializeConstStruct - copy all data elements (used for const types)
2861// initializePointers - copy pointers, zero non-pointers (used for non-const types on input)
2862// initializeDataMembers - copy non-pointers, retain pointers (used for non-const types on output)
2863type initializeStructMode uint
2864
2865const (
2866	initializeConstStruct = iota
2867	initializePointers
2868	initializeDataMembers
2869)
2870
2871func makeGuestInitializerList(mode initializeStructMode, name string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) []string {
2872	guest_initializer_list := []string{}
2873	var prefix string
2874	if mode == initializeDataMembers {
2875		prefix = "data_."
2876	} else {
2877		prefix = "new_value->"
2878	}
2879	return makeInitializerList(guest_initializer_list, mode, true, prefix, "origin_->", "", typе, host_arch, guest_arch)
2880}
2881
2882func makeGuestInitializerListForArray(mode initializeStructMode, name string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) []string {
2883	guest_initializer_list := []string{}
2884	var prefix string
2885	if mode == initializeDataMembers {
2886		prefix = "data_[index]."
2887	} else {
2888		prefix = "new_value[index]."
2889	}
2890	return makeInitializerList(guest_initializer_list, mode, true, prefix, "origin_[index].", "[index]", typе, host_arch, guest_arch)
2891}
2892
2893func makeHostInitializerList(mode initializeStructMode, name string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) []string {
2894	host_initializer_list := []string{}
2895	var prefix string
2896	if mode == initializeDataMembers {
2897		prefix = "data_."
2898	} else {
2899		prefix = fmt.Sprintf("ToHostAddr<GuestType<%s>>(ToGuestAddr(new_value))->", name)
2900	}
2901	return makeInitializerList(host_initializer_list, mode, false, prefix, "origin_->", "", typе, host_arch, guest_arch)
2902}
2903
2904func makeHostInitializerListForArray(mode initializeStructMode, name string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) []string {
2905	host_initializer_list := []string{}
2906	var prefix string
2907	if mode == initializeDataMembers {
2908		prefix = "data_[index]."
2909	} else {
2910		prefix = fmt.Sprintf("ToHostAddr<GuestType<%s>>(ToGuestAddr(new_value))[index].", name)
2911	}
2912	return makeInitializerList(host_initializer_list, mode, false, prefix, "origin_[index].", "[index]", typе, host_arch, guest_arch)
2913}
2914
2915func makeInitializerList(initializer_list []string, mode initializeStructMode, convert_to_guest bool, prefix, origin, index string, typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) []string {
2916	ids := typе.NumField(cpp_types.FirstArch)
2917	if mode == initializePointers {
2918		// We must ensure that last element produces output to properly generate "comma" variable below.
2919		for ids > 0 {
2920			if !isPtr(typе.Field(ids-1, cpp_types.FirstArch).Type()) {
2921				ids--
2922			} else {
2923				break
2924			}
2925		}
2926	}
2927	if ids == 0 {
2928		return initializer_list
2929	}
2930	for id := uint(0); id < ids; id++ {
2931		field_name := typе.Field(id, cpp_types.FirstArch).Name()
2932		field_type := typе.Field(id, cpp_types.FirstArch).Type()
2933		if mode == initializePointers {
2934			if !isPtr(field_type) && field_name != "sType" {
2935				continue
2936			}
2937		} else if initializeConstStruct == initializeConstStruct {
2938			field_type = cpp_types.ConstType(field_type)
2939		}
2940		field_type_name := targetTypeName(field_type, convert_to_guest)
2941		comma := ","
2942		if id == ids-1 {
2943			comma = ""
2944		}
2945		initializer := fmt.Sprintf(
2946			".%[1]s = %[2]s(%[3]s%[1]s)%[4]s", field_name, field_type_name, prefix, comma)
2947		field_kind := field_type.Kind(cpp_types.FirstArch)
2948		if field_kind == cpp_types.Const {
2949			field_type = field_type.Elem(cpp_types.FirstArch)
2950			field_kind = field_type.Kind(cpp_types.FirstArch)
2951		}
2952		switch field_kind {
2953		case cpp_types.Array:
2954			elem := field_type.Elem(cpp_types.FirstArch)
2955			field_type_name = targetTypeName(elem, convert_to_guest)
2956			initializer_list = append(initializer_list, fmt.Sprintf(".%s = {", field_name))
2957			max_index := field_type.NumField(cpp_types.FirstArch) - 1
2958			if max_index > 0 {
2959				for cur_index := uint(0); cur_index < max_index; cur_index++ {
2960					if isStruct(elem) && !isInputCompatible(field_type, host_arch, guest_arch) {
2961						initializer_list = append(initializer_list, field_type_name+"{")
2962						initializer_list = makeInitializerList(
2963							initializer_list,
2964							mode,
2965							convert_to_guest,
2966							fmt.Sprintf("%s%s[%d].", prefix, field_name, cur_index),
2967							fmt.Sprintf("%s%s[%d].", origin, field_name, cur_index),
2968							fmt.Sprintf("[%d]", origin, field_name, cur_index),
2969							elem,
2970							host_arch,
2971							guest_arch)
2972						initializer_list = append(initializer_list, "},")
2973						continue
2974					}
2975					initializer_list = append(initializer_list, fmt.Sprintf(
2976						"  %[2]s%[1]s[%[3]d],", field_name, prefix, cur_index))
2977				}
2978			}
2979			if isStruct(elem) && !isInputCompatible(field_type, host_arch, guest_arch) {
2980				initializer_list = append(initializer_list, field_type_name+"{")
2981				initializer_list = makeInitializerList(
2982					initializer_list,
2983					mode,
2984					convert_to_guest,
2985					fmt.Sprintf("%s%s[%d].", prefix, field_name, max_index),
2986					fmt.Sprintf("%s%s[%d].", origin, field_name, max_index),
2987					fmt.Sprintf("[%d]", origin, field_name, max_index),
2988					elem,
2989					host_arch,
2990					guest_arch)
2991				initializer_list = append(initializer_list, "}", "}"+comma)
2992			} else {
2993				initializer_list = append(initializer_list, fmt.Sprintf(
2994					"  %[2]s%[1]s[%[3]d]}%[4]s", field_name, prefix, max_index, comma))
2995			}
2996			continue
2997		case cpp_types.Ptr:
2998			initializer_fmt := ""
2999			if mode == initializeDataMembers {
3000				// When we are copying data members we have to keep pointers unchanged.
3001				initializer_fmt = ".%[1]s = %[6]s%[1]s%[8]s"
3002				// Most Vulkan data structures use "void*" or "const void*" types for the pNext field.
3003				// Only two data structures use something different: VkBaseInStructure/VkBaseOutStructure.
3004				// Handle them separately.
3005			} else if field_name == "pNext" {
3006				if field_type.Name(cpp_types.FirstArch) != "void *" && field_type.Name(cpp_types.FirstArch) != "const void *" {
3007					panic("Unsupported type of \"pNext\" field")
3008				}
3009				if mode == initializeConstStruct && !isPtrToConst(field_type) {
3010					if convert_to_guest {
3011						initializer_fmt = ".%[1]s = ConstCast<GuestType<void*>>(ConvertOptionalStructures(static_cast<const void*>(%[5]s%[1]s), holder.extensions_, out_of_memory))%[8]s"
3012					} else {
3013						initializer_fmt = ".%[1]s = const_cast<void *>(ConvertOptionalStructures(ConstCast<GuestType<const void*>>(%[5]s%[1]s), holder.extensions_, out_of_memory))%[8]s"
3014					}
3015				} else {
3016					if convert_to_guest {
3017						initializer_fmt = ".%[1]s = ConvertOptionalStructures(%[5]s%[1]s, holder.extensions_, out_of_memory)%[8]s"
3018					} else {
3019						initializer_fmt = ".%[1]s = ConvertOptionalStructures(%[5]s%[1]s, holder.extensions_, out_of_memory)%[8]s"
3020					}
3021				}
3022			} else if doesNeedHolder(field_type, host_arch, guest_arch) {
3023				// VkCommandBufferBeginInfo has field pInheritanceInfo which may or may not be used and it's quite hard to determine if it can be touched.
3024				// Because it's part of Vulkan API and can not be changed we are doing complex dance with maps and lock on the input side.
3025				// When layers are involved, though, we assume that nullptr that we are introducing here would pass to other layers thus there is
3026				// no need to deal with this problem in the GuestRunners.
3027				if !convert_to_guest && field_name == "pInheritanceInfo" && typе.Name(cpp_types.FirstArch) == "struct VkCommandBufferBeginInfo" {
3028					initializer_fmt = ".%[1]s = has_inheritance_info ? ToHostType(%[5]s%[1]s, holder.%[1]s_holder_%[7]s%[4]s, out_of_memory) : nullptr%[8]s"
3029					// pImageInfo is marked with noautovalidity="true" and there's the following comment:
3030					//   Sampler, image view, and layout for SAMPLER, COMBINED_IMAGE_SAMPLER, {SAMPLED,STORAGE}_IMAGE, and INPUT_ATTACHMENT descriptor types.
3031					// Replace it with nullptr if descriptor type is not in the five listed ones.
3032				} else if !convert_to_guest && field_name == "pImageInfo" && typе.Name(cpp_types.FirstArch) == "struct VkWriteDescriptorSet" {
3033					initializer_fmt = `.%[1]s =
3034                    (VkDescriptorType(ToHostAddr<GuestType<VkWriteDescriptorSet>>(ToGuestAddr(new_value))[index].descriptorType) == BERBERIS_VK_DESCRIPTOR_TYPE_SAMPLER ||
3035                     VkDescriptorType(ToHostAddr<GuestType<VkWriteDescriptorSet>>(ToGuestAddr(new_value))[index].descriptorType) == BERBERIS_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
3036                     VkDescriptorType(ToHostAddr<GuestType<VkWriteDescriptorSet>>(ToGuestAddr(new_value))[index].descriptorType) == BERBERIS_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
3037                     VkDescriptorType(ToHostAddr<GuestType<VkWriteDescriptorSet>>(ToGuestAddr(new_value))[index].descriptorType) == BERBERIS_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ||
3038                     VkDescriptorType(ToHostAddr<GuestType<VkWriteDescriptorSet>>(ToGuestAddr(new_value))[index].descriptorType) == BERBERIS_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ?
3039                     ToHostType(%[5]s%[1]s, holder.%[1]s_holder_%[7]s%[4]s, out_of_memory): nullptr%[8]s`
3040				} else {
3041					if convert_to_guest {
3042						initializer_fmt = ".%[1]s = GuestType<%[2]s>(%[5]s%[1]s, holder.%[1]s_holder_%[7]s%[4]s, out_of_memory)%[8]s"
3043					} else {
3044						initializer_fmt = ".%[1]s = ToHostType(%[5]s%[1]s, holder.%[1]s_holder_%[7]s%[4]s, out_of_memory)%[8]s"
3045					}
3046				}
3047			} else if isPtrToFunc(field_type) {
3048				if convert_to_guest {
3049					initializer_fmt = ".%[1]s = WrapHostFunctionIfNeeded(%[5]s%[1]s, \"%[1]s\")%[8]s"
3050				} else {
3051					initializer_fmt = ".%[1]s = WrapGuestFunctionIfNeeded(GuestType<%[3]s>(%[5]s%[1]s), \"%[1]s\")%[8]s"
3052				}
3053			}
3054			if initializer_fmt != "" {
3055				field_length := typе.Field(id, cpp_types.FirstArch).BaseFieldInfo().(vulkan_xml.ExtendedFieldInfo).Length()
3056				field_length_ref := ""
3057				if field_length != nil {
3058					if mode == initializeConstStruct && !isPtrToConst(field_type) {
3059						if convert_to_guest {
3060							field_length_ref = ", &" + prefix + field_length.Name()
3061						} else {
3062							// After taking address we end up with weird “GuestType<GuestType<std::uint32_t>*>” which we can only  convert to “const ::uint32_t*” using bit_cast
3063							field_length_ref = ", bit_cast<const ::uint32_t*>(&" + prefix + field_length.Name() + ")"
3064						}
3065					} else {
3066						field_length_ref = ", " + prefix + field_length.Name()
3067					}
3068				}
3069				initializer = fmt.Sprintf(initializer_fmt, field_name, field_type.Name(cpp_types.FirstArch), field_type_name, field_length_ref, prefix, origin, index, comma)
3070			}
3071		case cpp_types.Struct:
3072			if !isInputCompatible(field_type, host_arch, guest_arch) {
3073				initializer_list = append(initializer_list, fmt.Sprintf(
3074					".%[1]s = %[2]s{", field_name, field_type_name))
3075				initializer_list = makeInitializerList(
3076					initializer_list,
3077					mode,
3078					convert_to_guest,
3079					prefix+field_name+".",
3080					origin+field_name+".",
3081					"",
3082					field_type,
3083					host_arch,
3084					guest_arch)
3085				initializer = "}" + comma
3086			}
3087		case cpp_types.Union:
3088			// Temprorary kludge.
3089			if field_type.BaseName(cpp_types.FirstArch) == "VkDescriptorDataEXT" {
3090				continue
3091			}
3092			if !isInputCompatible(field_type, cpp_types.X86, cpp_types.Arm) ||
3093				!isInputCompatible(field_type, cpp_types.X86_64, cpp_types.Arm64) {
3094				panic("Unsupported union field in incompatible type: " + typе.Name(cpp_types.FirstArch) + " " + field_name)
3095			}
3096		}
3097		initializer_list = append(initializer_list, initializer)
3098	}
3099	return initializer_list
3100}
3101func targetTypeName(typе cpp_types.Type, convert_to_guest bool) string {
3102	if isConst(typе) {
3103		typе = typе.Elem(cpp_types.FirstArch)
3104	}
3105	type_name := typе.Name(cpp_types.FirstArch)
3106	// Outer const just makes conversion harder and doesn't affect anything, really,
3107	// since we are only producing temporary object here which would be assigned to
3108	// proper const field.
3109	if convert_to_guest {
3110		type_name = fmt.Sprintf("GuestType<%s>", type_name)
3111	} else {
3112		switch typе.Kind(cpp_types.FirstArch) {
3113		case cpp_types.Struct, cpp_types.Union:
3114			type_name = typе.BaseName(cpp_types.FirstArch)
3115		case cpp_types.Ptr:
3116			if !isPtrToFunc(typе) {
3117				type_name = "ToHostAddr"
3118			}
3119		}
3120	}
3121	return type_name
3122}
3123
3124func doesNeedHolder(typе cpp_types.Type, host_arch cpp_types.Arch, guest_arch cpp_types.Arch) bool {
3125	if isInputCompatible(typе, host_arch, guest_arch) {
3126		return false
3127	}
3128	// We are not trying to convert on ARM64 because we don't know if pointer is valid (and if all extensions are compatible).
3129	// On ARM32 we need to convert some data structures, but tests pass because of quirk of how they are run.
3130	// TODO(b/274875580): fix properly.
3131	if guest_arch == cpp_types.Arm64 && typе.Name(cpp_types.Arm64) == "const struct VkCommandBufferInheritanceInfo *" {
3132		return false
3133	}
3134	kind := typе.Kind(cpp_types.FirstArch)
3135	switch kind {
3136	// We need holders when we are working with pointers to structures.
3137	// But pointers to function don't need holders (even if then need coversion routines).
3138	case cpp_types.Ptr:
3139		pointee := typе.Elem(cpp_types.FirstArch)
3140		if isConst(pointee) {
3141			pointee = pointee.Elem(cpp_types.FirstArch)
3142		}
3143		if isStruct(pointee) || isUnion(pointee) {
3144			return true
3145		} else if isFunc(pointee) {
3146			return false
3147		} else {
3148			panic("Unsupported field in incompatible type: " + typе.Name(cpp_types.FirstArch))
3149		}
3150	case cpp_types.Struct, cpp_types.Union:
3151		ids := typе.NumField(cpp_types.FirstArch)
3152		for id := uint(0); id < ids; id++ {
3153			field_type := typе.Field(id, cpp_types.FirstArch).Type()
3154			if doesNeedHolder(field_type, host_arch, guest_arch) {
3155				return true
3156			}
3157		}
3158	}
3159	return false
3160}
3161
3162func printHostStructVerification(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) error {
3163	for _, name := range sorted_type_names {
3164		typе := types[name]
3165		if !isStruct(typе) && !isUnion(typе) {
3166			continue
3167		}
3168		fields_check_berberis_host := []string{}
3169		fields_check_platform_host := []string{}
3170		for i := uint(0); i < typе.NumField(host_arch); i++ {
3171			field := typе.Field(i, host_arch)
3172			var field_offset uint
3173			if !isUnion(typе) {
3174				field_offset = field.(cpp_types.StructFieldInfo).Offset()
3175			} else {
3176				field_offset = 0
3177			}
3178			fields_check_berberis_host = append(fields_check_berberis_host,
3179				fmt.Sprintf("CHECK_FIELD_LAYOUT(berberis::%[1]s, %[2]s, %[3]d, %[4]d);",
3180					name,
3181					field.Name(),
3182					field_offset,
3183					field.Type().Bits(host_arch)))
3184			fields_check_platform_host = append(fields_check_platform_host,
3185				fmt.Sprintf("CHECK_FIELD_LAYOUT(::%[1]s, %[2]s, %[3]d, %[4]d);",
3186					name,
3187					field.Name(),
3188					field_offset,
3189					field.Type().Bits(host_arch)))
3190		}
3191		fields_check_berberis_guest := []string{}
3192		fields_check_platform_guest := []string{}
3193		for i := uint(0); i < typе.NumField(guest_arch); i++ {
3194			field := typе.Field(i, guest_arch)
3195			var field_offset uint
3196			if !isUnion(typе) {
3197				field_offset = field.(cpp_types.StructFieldInfo).Offset()
3198			} else {
3199				field_offset = 0
3200			}
3201			fields_check_berberis_guest = append(fields_check_berberis_guest,
3202				fmt.Sprintf("CHECK_FIELD_LAYOUT(berberis::%[1]s, %[2]s, %[3]d, %[4]d);",
3203					name,
3204					field.Name(),
3205					field_offset,
3206					field.Type().Bits(guest_arch)))
3207			fields_check_platform_guest = append(fields_check_platform_guest,
3208				fmt.Sprintf("CHECK_FIELD_LAYOUT(::%[1]s, %[2]s, %[3]d, %[4]d);",
3209					name,
3210					field.Name(),
3211					field_offset,
3212					field.Type().Bits(guest_arch)))
3213		}
3214		_, err := fmt.Fprintf(
3215			w,
3216			`#if %[7]s
3217CHECK_STRUCT_LAYOUT(berberis::%[2]s, %[3]d, %[4]d);
3218%[9]s
3219#if !defined(BERBERIS_%[1]s)
3220CHECK_STRUCT_LAYOUT(::%[2]s, %[3]d, %[4]d);
3221%[10]s
3222#endif  /* BERBERIS_%[1]s */
3223#elif %[8]s
3224CHECK_STRUCT_LAYOUT(berberis::%[2]s, %[5]d, %[6]d);
3225%[11]s
3226#if !defined(BERBERIS_%[1]s)
3227CHECK_STRUCT_LAYOUT(::%[2]s, %[5]d, %[6]d);
3228%[12]s
3229#endif  /* BERBERIS_%[1]s */
3230#else
3231#error Unsupported architecture.
3232#endif
3233
3234`,
3235			toEnumNameWithSuffix(name, "NOVERIFY"),
3236			name,
3237			typе.Bits(host_arch),
3238			typе.Align(host_arch),
3239			typе.Bits(guest_arch),
3240			typе.Align(guest_arch),
3241			cpp_types.Define(host_arch),
3242			cpp_types.Define(guest_arch),
3243			strings.Join(fields_check_berberis_host, "\n"),
3244			strings.Join(fields_check_platform_host, "\n"),
3245			strings.Join(fields_check_berberis_guest, "\n"),
3246			strings.Join(fields_check_platform_guest, "\n"))
3247		if err != nil {
3248			return err
3249		}
3250	}
3251	return nil
3252}
3253
3254func printGuestStructVerification(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) error {
3255	for _, name := range sorted_type_names {
3256		typе := types[name]
3257		if typе.Kind(guest_arch) != cpp_types.Struct &&
3258			typе.Kind(guest_arch) != cpp_types.Union {
3259			continue
3260		}
3261		if isInputCompatible(typе, host_arch, guest_arch) {
3262			continue
3263		}
3264		for _, cоnst := range []string{"", "const "} {
3265			_, err := fmt.Fprintf(
3266				w,
3267				"CHECK_STRUCT_LAYOUT(berberis::GuestType<%s berberis::%s>, %d, %d);\n",
3268				cоnst,
3269				name,
3270				typе.Bits(guest_arch),
3271				typе.Align(guest_arch))
3272			if err != nil {
3273				return err
3274			}
3275			for i := uint(0); i < typе.NumField(cpp_types.FirstArch); i++ {
3276				field := typе.Field(i, guest_arch)
3277				field_type := field.Type()
3278				var field_name string
3279				var field_offset uint
3280				if typе.Kind(guest_arch) == cpp_types.Struct {
3281					field_name = field.Name()
3282					field_offset = field.(cpp_types.StructFieldInfo).Offset()
3283				} else {
3284					field_name = "uniоn." + field.Name()
3285					field_offset = 0
3286				}
3287				_, err = fmt.Fprintf(
3288					w,
3289					"CHECK_FIELD_LAYOUT(berberis::GuestType<%s berberis::%s>, %s, %d, %d);\n",
3290					cоnst,
3291					name,
3292					field_name,
3293					field_offset,
3294					field_type.Bits(guest_arch))
3295				if err != nil {
3296					return err
3297				}
3298			}
3299			_, err = fmt.Fprintln(w, "")
3300			if err != nil {
3301				return err
3302			}
3303		}
3304	}
3305	return nil
3306}
3307
3308func printConvertOptionalStructures(w io.Writer, sorted_type_names []string, types map[string]cpp_types.Type, conversion map[string]*NeededConvertor, host_arch, guest_arch cpp_types.Arch) (err error) {
3309	var compatible_structs []string
3310	var convert_guest_in_structure []string
3311	var convert_host_in_structure []string
3312	var convert_guest_out_structure []string
3313	var convert_host_out_structure []string
3314	for _, name := range sorted_type_names {
3315		typе := types[name]
3316		if isUnion(typе) {
3317			continue
3318		}
3319		if !typе.(vulkan_xml.ExtendedStructInfo).OptionalStruct() {
3320			continue
3321		}
3322		optional_value := typе.(vulkan_xml.ExtendedStructInfo).OptionalValue()
3323		if cpp_types.IsInputCompatible(typе, host_arch, guest_arch) {
3324			compatible_structs = append(compatible_structs, "BERBERIS_"+optional_value)
3325		}
3326		if conversion[name].need_base_convertor {
3327			convert_guest_out_structure = append(convert_guest_out_structure, fmt.Sprintf(`      case %[1]s: {
3328        auto new_holder = new (std::nothrow) GuestType<%[2]s*>::HostHolder;
3329        if (new_holder == nullptr) {
3330            out_of_memory = true;
3331            return nullptr;
3332        }
3333        new_holder->extensions_ = std::move(holder);
3334        holder.reset(new_holder);
3335        auto* converted_type = ToHostType(StaticCast<GuestType<%[2]s*>>(StaticCast<GuestType<void*>>(ptr)), *new_holder, out_of_memory);
3336        if (out_of_memory) {
3337            return nullptr;
3338        }
3339        return converted_type;
3340     }
3341`,
3342				"BERBERIS_"+optional_value,
3343				name))
3344			convert_host_out_structure = append(convert_host_out_structure, fmt.Sprintf(`      case %[1]s: {
3345        auto new_holder = new (std::nothrow) GuestType<%[2]s*>::GuestHolder;
3346        if (new_holder == nullptr) {
3347            out_of_memory = true;
3348            return nullptr;
3349        }
3350        new_holder->extensions_ = std::move(holder);
3351        holder.reset(new_holder);
3352        auto converted_type = StaticCast<GuestType<void*>>(GuestType<%[2]s*>(static_cast<%[2]s*>(static_cast<void*>(ptr)), *new_holder, out_of_memory));
3353        if (out_of_memory) {
3354            return nullptr;
3355        }
3356        return converted_type;
3357     }
3358`,
3359				"BERBERIS_"+optional_value,
3360				name))
3361		}
3362		if conversion[name].need_const_convertor {
3363			convert_guest_in_structure = append(convert_guest_in_structure, fmt.Sprintf(`      case %[1]s: {
3364        auto new_holder = new (std::nothrow) GuestType<const %[2]s*>::HostHolder;
3365        if (new_holder == nullptr) {
3366            out_of_memory = true;
3367            return nullptr;
3368        }
3369        new_holder->extensions_ = std::move(holder);
3370        holder.reset(new_holder);
3371        auto* converted_type = ToHostType(StaticCast<GuestType<const %[2]s*>>(StaticCast<GuestType<const void*>>(ptr)), *new_holder, out_of_memory);
3372        if (out_of_memory) {
3373            return nullptr;
3374        }
3375        return converted_type;
3376     }
3377`,
3378				"BERBERIS_"+optional_value,
3379				name))
3380			convert_host_in_structure = append(convert_host_in_structure, fmt.Sprintf(`      case %[1]s: {
3381        auto new_holder = new (std::nothrow) GuestType<const %[2]s*>::GuestHolder;
3382        if (new_holder == nullptr) {
3383            out_of_memory = true;
3384            return nullptr;
3385        }
3386        new_holder->extensions_ = std::move(holder);
3387        holder.reset(new_holder);
3388        auto converted_type = StaticCast<GuestType<const void*>>(GuestType<const %[2]s*>(static_cast<const %[2]s*>(static_cast<const void*>(ptr)), *new_holder, out_of_memory));
3389        if (out_of_memory) {
3390            return nullptr;
3391        }
3392        return converted_type;
3393     }
3394`,
3395				"BERBERIS_"+optional_value,
3396				name))
3397		}
3398	}
3399
3400	_, err = fmt.Fprintf(w,
3401		`
3402bool AreAllOptionalStructuresCompatible(GuestType<const void*> head) {
3403  for (auto ptr = StaticCast<GuestType<const VkBaseInStructure*>>(head); ToGuestAddr(ptr) != kNullGuestAddr; ptr = ToHostAddr<GuestType<VkBaseInStructure>>(ToGuestAddr(ptr))->pNext) {
3404    switch (VkStructureType(ToHostAddr<GuestType<const VkBaseInStructure>>(ToGuestAddr(ptr))->sType)) {
3405      case %[1]s:
3406        continue;
3407      default:
3408        return false;
3409    }
3410  }
3411  return true;
3412}
3413
3414bool AreAllOptionalStructuresCompatible(GuestType<void*> head) {
3415  for (auto ptr = StaticCast<GuestType<VkBaseOutStructure*>>(head); ToGuestAddr(ptr) != kNullGuestAddr; ptr = ToHostAddr<GuestType<VkBaseOutStructure>>(ToGuestAddr(ptr))->pNext) {
3416    switch (VkStructureType(ToHostAddr<GuestType<VkBaseOutStructure>>(ToGuestAddr(ptr))->sType)) {
3417      case %[1]s:
3418        continue;
3419      default:
3420        return false;
3421    }
3422  }
3423  return true;
3424}
3425
3426bool AreAllOptionalStructuresCompatible(const void* head) {
3427  for (auto* ptr = static_cast<const VkBaseInStructure*>(head); ptr != nullptr; ptr = ptr->pNext) {
3428    switch (ptr->sType) {
3429      case %[1]s:
3430        continue;
3431      default:
3432        return false;
3433    }
3434  }
3435  return true;
3436}
3437
3438bool AreAllOptionalStructuresCompatible(void* head) {
3439  for (auto* ptr = static_cast<VkBaseOutStructure*>(head); ptr != nullptr; ptr = ptr->pNext) {
3440    switch (ptr->sType) {
3441      case %[1]s:
3442        continue;
3443      default:
3444        return false;
3445    }
3446  }
3447  return true;
3448}
3449
3450const void* ConvertOptionalStructures(GuestType<const void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory) {
3451  if (AreAllOptionalStructuresCompatible(head)) {
3452    return ToHostAddr(head);
3453  }
3454  for (auto ptr = StaticCast<GuestType<const VkBaseInStructure*>>(head); ToGuestAddr(ptr) != kNullGuestAddr; ptr = ToHostAddr<GuestType<VkBaseInStructure>>(ToGuestAddr(ptr))->pNext) {
3455    switch (VkStructureType(ToHostAddr<GuestType<const VkBaseInStructure>>(ToGuestAddr(ptr))->sType)) {
3456%[2]s
3457      default:
3458        continue;
3459    }
3460  }
3461  return nullptr;
3462}
3463
3464void* ConvertOptionalStructures(GuestType<void*> head, std::unique_ptr<HostHolderBase>& holder, bool& out_of_memory) {
3465  if (AreAllOptionalStructuresCompatible(head)) {
3466    return ToHostAddr(head);
3467  }
3468  for (auto ptr = StaticCast<GuestType<VkBaseOutStructure*>>(head); ToGuestAddr(ptr) != kNullGuestAddr; ptr = ToHostAddr<GuestType<VkBaseOutStructure>>(ToGuestAddr(ptr))->pNext) {
3469    switch (VkStructureType(ToHostAddr<GuestType<const VkBaseOutStructure>>(ToGuestAddr(ptr))->sType)) {
3470%[3]s
3471      default:
3472        continue;
3473    }
3474  }
3475  return nullptr;
3476}
3477
3478GuestType<const void*> ConvertOptionalStructures(const void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory) {
3479  if (AreAllOptionalStructuresCompatible(head)) {
3480    return GuestType<const void*>(head);
3481  }
3482  for (auto ptr = static_cast<const VkBaseInStructure*>(head); ptr != nullptr; ptr = ptr->pNext) {
3483    switch (ptr->sType) {
3484%[4]s
3485      default:
3486        continue;
3487    }
3488  }
3489  return GuestType<const void*>(nullptr);
3490}
3491
3492GuestType<void*> ConvertOptionalStructures(void* head, std::unique_ptr<GuestHolderBase>& holder, bool& out_of_memory) {
3493  if (AreAllOptionalStructuresCompatible(head)) {
3494    return GuestType<void*>(head);
3495  }
3496  for (auto ptr = static_cast<VkBaseOutStructure*>(head); ptr != nullptr; ptr = ptr->pNext) {
3497    switch (ptr->sType) {
3498%[5]s
3499      default:
3500        continue;
3501    }
3502  }
3503  return GuestType<void*>(nullptr);
3504}
3505
3506`,
3507		strings.Join(compatible_structs, ":\n      case "),
3508		strings.Join(convert_guest_in_structure, ""),
3509		strings.Join(convert_guest_out_structure, ""),
3510		strings.Join(convert_host_in_structure, ""),
3511		strings.Join(convert_host_out_structure, ""))
3512	if err != nil {
3513		return err
3514	}
3515	return nil
3516}
3517
3518func printCustomTrampolies(w io.Writer, sorted_command_names []string, commands map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) (err error) {
3519	for _, name := range sorted_command_names {
3520		vfp := ""
3521		if guest_arch == cpp_types.Arm {
3522			vfp = ", GuestAbi::kAapcsVfp"
3523		}
3524		command := commands[name]
3525		param_names := []string{}
3526		variable_declarations := []string{}
3527		params_are_compatible := true
3528		for i := uint(0); i < command.NumField(cpp_types.FirstArch); i++ {
3529			param_name := command.Field(i, cpp_types.FirstArch).Name()
3530			param_type := command.Field(i, cpp_types.FirstArch).Type()
3531			param_names = append(param_names, param_name)
3532			if isInputCompatible(param_type, host_arch, guest_arch) {
3533				variable_declarations = append(variable_declarations, fmt.Sprintf(
3534					"%s = %s_guest", param_type.DeclareVar(param_name+"_host", cpp_types.FirstArch), param_name))
3535			} else {
3536				params_are_compatible = false
3537				param_length := command.Field(i, cpp_types.FirstArch).BaseFieldInfo().(vulkan_xml.ExtendedFieldInfo).Length()
3538				if param_length == nil {
3539					variable_declarations = append(
3540						variable_declarations,
3541						fmt.Sprintf("GuestType<%s>::HostHolder %s_holder", param_type.Name(cpp_types.FirstArch), param_name),
3542						fmt.Sprintf(
3543							"%[1]s = ToHostType(%[2]s_guest, %[2]s_holder, out_of_memory)",
3544							param_type.DeclareVar(param_name+"_host", cpp_types.FirstArch),
3545							param_name))
3546				} else {
3547					variable_declarations = append(
3548						variable_declarations,
3549						fmt.Sprintf("GuestType<%s>::HostArrayHolder %s_holder", param_type.Name(cpp_types.FirstArch), param_name),
3550						fmt.Sprintf(
3551							"%[1]s = ToHostType(%[2]s_guest, %[2]s_holder, %[3]s_host, out_of_memory)",
3552							param_type.DeclareVar(param_name+"_host", cpp_types.FirstArch),
3553							param_name,
3554							param_length.Name()))
3555				}
3556			}
3557		}
3558		// vkAllocateCommandBuffers and vkBeginCommandBuffer are manually written to handle awful pInheritanceInfo field.
3559		// The VkCommandBufferBeginInfo data structure doesn't include any clue which may allow someone to understand if
3560		// that field can be used or not.  Instead that information is only available in entirely different time and place
3561		// when vkAllocateCommandBuffers functions is called.
3562		// To handle VkCommandBufferBeginInfo we need side-channel to pass that boolean from vkAllocateCommandBuffers to
3563		// vkBeginCommandBuffer, that's why we need to skip automatically generation of converter.
3564		if params_are_compatible || name == "vkAllocateCommandBuffers" || name == "vkBeginCommandBuffer" {
3565			continue
3566		}
3567		declare_ret := ""
3568		if command.Elem(cpp_types.FirstArch).Kind(cpp_types.FirstArch) != cpp_types.Void {
3569			declare_ret = fmt.Sprintf("auto&& [ret] = GuestReturnReference<PFN_%s%s>(state);\n  ret = ", name, vfp)
3570		}
3571		_, err = fmt.Fprintf(w, `void DoCustomTrampolineWithThunk_%[1]s(HostCode callee, ProcessState* state) {
3572  PFN_%[1]s callee_function = AsFuncPtr(callee);
3573  auto [%[3]s_guest] = GuestParamsValues<PFN_%[1]s%[2]s>(state);
3574  [[maybe_unused]] bool out_of_memory;
3575  %[5]s;
3576  %[6]scallee_function(%[4]s_host);
3577}
3578
3579`,
3580			name,
3581			vfp,
3582			strings.Join(param_names, "_guest, "),
3583			strings.Join(param_names, "_host, "),
3584			strings.Join(variable_declarations, ";\n  "),
3585			declare_ret)
3586		if err != nil {
3587			return err
3588		}
3589	}
3590	return nil
3591}
3592
3593func printCustomGuestRunners(w io.Writer, sorted_command_names []string, commands map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) (err error) {
3594	for _, name := range sorted_command_names {
3595		command := commands[name]
3596		param_names := []string{}
3597		variable_declarations := []string{}
3598		params_are_compatible := true
3599		for i := uint(0); i < command.NumField(cpp_types.FirstArch); i++ {
3600			param_name := command.Field(i, cpp_types.FirstArch).Name()
3601			param_type := command.Field(i, cpp_types.FirstArch).Type()
3602			param_names = append(param_names, param_name)
3603			if isInputCompatible(param_type, host_arch, guest_arch) {
3604				variable_declarations = append(variable_declarations, fmt.Sprintf(
3605					"%[1]s_guest = %[1]s_host", param_name))
3606			} else {
3607				params_are_compatible = false
3608				param_length := command.Field(i, cpp_types.FirstArch).BaseFieldInfo().(vulkan_xml.ExtendedFieldInfo).Length()
3609				if param_length == nil {
3610					variable_declarations = append(
3611						variable_declarations,
3612						fmt.Sprintf("GuestType<%s>::GuestHolder %s_holder", param_type.Name(cpp_types.FirstArch), param_name),
3613						fmt.Sprintf(
3614							"%[2]s_guest = GuestType<%[1]s>(%[2]s_host, %[2]s_holder, out_of_memory)",
3615							param_type.Name(cpp_types.FirstArch),
3616							param_name))
3617				} else {
3618					variable_declarations = append(
3619						variable_declarations,
3620						fmt.Sprintf("GuestType<%s>::GuestArrayHolder %s_holder", param_type.Name(cpp_types.FirstArch), param_name),
3621						fmt.Sprintf(
3622							"%[2]s_guest = GuestType<%[1]s>(%[2]s_host, %[2]s_holder, %[3]s_host, out_of_memory)",
3623							param_type.Name(cpp_types.FirstArch),
3624							param_name,
3625							param_length.Name()))
3626				}
3627			}
3628		}
3629		// vkCreateInstance needs additional non-trivial processing.
3630		if params_are_compatible || name == "vkCreateInstance" {
3631			continue
3632		}
3633		_, err = fmt.Fprintf(w, `void RunGuest_%[1]s(GuestAddr pc, GuestArgumentBuffer* buf) {
3634  auto [%[3]s_host] = HostArgumentsValues<PFN_%[1]s>(buf);
3635  {
3636    [[maybe_unused]] bool out_of_memory;
3637    auto [%[2]s_guest] = GuestArgumentsReferences<PFN_%[1]s>(buf);
3638    %[4]s;
3639    RunGuestCall(pc, buf);
3640  }
3641}
3642
3643`,
3644			name,
3645			strings.Join(param_names, "_guest, "),
3646			strings.Join(param_names, "_host, "),
3647			strings.Join(variable_declarations, ";\n    "))
3648		if err != nil {
3649			return err
3650		}
3651	}
3652	return nil
3653}
3654
3655func printExtensionsMap(w io.Writer, extensions map[string]int64) (err error) {
3656	names := make([]string, 0, len(extensions))
3657	for extension := range extensions {
3658		names = append(names, fmt.Sprintf("{\"%s\", %d}", extension, extensions[extension]))
3659	}
3660	sort.Strings(names)
3661	_, err = fmt.Fprintf(w, `
3662struct ExtensionInfo {
3663  const char* name;
3664  uint32_t maxsupported_spec;
3665};
3666
3667[[maybe_unused]] auto& GetExtensionsMap() {
3668#if defined(__i386__)
3669  static constexpr std::array<ExtensionInfo, %[1]d> map{
3670#else
3671  static constexpr std::array<ExtensionInfo, %[2]d> map{
3672#endif
3673      {%[3]s}};
3674  static_assert(IsSorted(std::begin(map), std::end(map), StrCmpLessName));
3675  return map;
3676}
3677
3678`,
3679		len(extensions)-1,
3680		len(extensions),
3681		// Disable VK_EXT_device_memory_report extension only for arm32.
3682		strings.Replace(
3683			strings.Join(names, ",\n       "),
3684			"       {\"VK_EXT_device_memory_report\", 2},\n",
3685			`#if !defined(__i386__)
3686       {"VK_EXT_device_memory_report", 2},
3687#endif
3688`,
3689			1))
3690	return nil
3691}
3692
3693func printMaps(w io.Writer, sorted_command_names []string, commands map[string]cpp_types.Type, host_arch, guest_arch cpp_types.Arch) (err error) {
3694	command_trampolines := []string{}
3695	command_wrappers := []string{}
3696	for _, name := range sorted_command_names {
3697		command := commands[name]
3698		params_are_compatible := true
3699		switch name {
3700		// These functions are compatible based on signatures, but actually need special processing.
3701		case "vkGetDeviceProcAddr", "vkGetInstanceProcAddr":
3702			params_are_compatible = false
3703		}
3704		for i := uint(0); i < command.NumField(guest_arch); i++ {
3705			param_type := command.Field(i, guest_arch).Type()
3706			if !isInputCompatible(param_type, host_arch, guest_arch) {
3707				params_are_compatible = false
3708				break
3709			}
3710		}
3711		// Data structures in vkEnumerate{Device,Instance}ExtensionProperties are compatible,
3712		// but we need to filter out unsupported extensions.
3713		// Data structures in vkFreeCommandBuffers are compatible but we need to free memory
3714		// allocated for meta-information in vkAllocateCommandBuffers.
3715		if params_are_compatible && name != "vkEnumerateDeviceExtensionProperties" && name != "vkEnumerateInstanceExtensionProperties" && name != "vkFreeCommandBuffers" {
3716			if guest_arch == cpp_types.Arm {
3717				command_trampolines = append(command_trampolines, fmt.Sprintf(
3718					"{\"%s\", GetTrampolineFunc<%s, GuestAbi::kAapcsVfp>()}", name, command.Name(guest_arch)))
3719			} else {
3720				command_trampolines = append(command_trampolines, fmt.Sprintf(
3721					"{\"%s\", GetTrampolineFunc<%s>()}", name, command.Name(guest_arch)))
3722			}
3723		} else {
3724			command_trampolines = append(command_trampolines, fmt.Sprintf(
3725				"{\"%[1]s\", DoCustomTrampolineWithThunk_%[1]s}", name))
3726		}
3727		// Data structures in vkEnumerate{Device,Instance}ExtensionProperties are compatible,
3728		// but we need to filter out unsupported extensions.
3729		if params_are_compatible && name != "vkEnumerateDeviceExtensionProperties" && name != "vkEnumerateInstanceExtensionProperties" {
3730			command_wrappers = append(command_wrappers, fmt.Sprintf(
3731				"{\"%[1]s\", [](GuestAddr pc) { return WrapGuestFunctionImpl(pc, kGuestFunctionWrapperSignature<%[2]s>, RunGuestCall, \"%[1]s\"); }}",
3732				name,
3733				command.Name(guest_arch)))
3734		} else {
3735			command_wrappers = append(command_wrappers, fmt.Sprintf(
3736				"{\"%[1]s\", [](GuestAddr pc) { return WrapGuestFunctionImpl(pc, kGuestFunctionWrapperSignature<%[2]s>, RunGuest_%[1]s, \"%[1]s\"); }}",
3737				name,
3738				command.Name(guest_arch)))
3739		}
3740	}
3741	_, err = fmt.Fprintf(w, `auto& GetMapForvkGetProcAddr() {
3742  static constexpr std::array<NamedTrampolineFunc, %[1]d> map{
3743      {%[2]s}};
3744  static_assert(IsSorted(std::begin(map), std::end(map), StrCmpLessName));
3745  return map;
3746}
3747
3748auto& GetMapForRunGuestvkGetInstanceProcAddr() {
3749  static constexpr std::array<NamedGuestFunctionWrapper, %[1]d> map{
3750      {%[3]s}};
3751  static_assert(IsSorted(std::begin(map), std::end(map), StrCmpLessName));
3752  return map;
3753}
3754
3755`,
3756		len(sorted_command_names),
3757		strings.Join(command_trampolines, ",\n        "),
3758		strings.Join(command_wrappers, ",\n       "))
3759	if err != nil {
3760		return err
3761	}
3762	return nil
3763}
3764
3765// The same name as in generator.py in vulkan_headers package
3766func toEnumNameWithSuffix(name, mark string) string {
3767	split_point := len(name)
3768	for isAsciiUpperCase(rune(name[split_point-1])) {
3769		split_point--
3770		if split_point == 0 {
3771			split_point = len(name)
3772			break
3773		}
3774	}
3775	var enum_name_with_suffix string
3776	for _, runе := range name[0:split_point] {
3777		if isAsciiUpperCase(runе) &&
3778			len(enum_name_with_suffix) > 0 &&
3779			isAsciiLowerCase(rune(enum_name_with_suffix[len(enum_name_with_suffix)-1])) {
3780			enum_name_with_suffix += string('_')
3781		}
3782		enum_name_with_suffix += string(runе)
3783	}
3784	enum_name_with_suffix += "_" + mark
3785	if split_point != len(name) {
3786		enum_name_with_suffix += "_" + name[split_point:]
3787	}
3788	return strings.ToUpper(enum_name_with_suffix)
3789}
3790
3791func isAsciiUpperCase(runе rune) bool {
3792	return 'A' <= runе && runе <= 'Z'
3793}
3794
3795func isAsciiLowerCase(runе rune) bool {
3796	return '0' <= runе && runе <= '9' || 'a' <= runе && runе <= 'z' || runе == '_'
3797}
3798
3799func isInputCompatible(typе cpp_types.Type, host_arch, guest_arch cpp_types.Arch) bool {
3800	if isPtrToAlias(typе) {
3801		return isInputCompatible(typе.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch), host_arch, guest_arch)
3802	}
3803	if isPtrToConstAlias(typе) {
3804		return isInputCompatible(typе.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch), host_arch, guest_arch)
3805	}
3806	if isPtrToStruct(typе) {
3807		return isInputCompatible(typе.Elem(cpp_types.FirstArch), host_arch, guest_arch)
3808	}
3809	if isPtrToConstStruct(typе) {
3810		return isInputCompatible(typе.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch), host_arch, guest_arch)
3811	}
3812	// TODO(b/171255170): remove when arrays conversion in optional structures would be supported.
3813	if typе.Name(cpp_types.FirstArch) == "struct VkDrmFormatModifierProperties2EXT" {
3814		return true
3815	}
3816	// TODO(b/171255170): remove when conversion of optional structures in callbacks would be supported.
3817	if typе.Name(cpp_types.FirstArch) == "struct VkDebugUtilsMessengerCallbackDataEXT" || typе.Name(cpp_types.FirstArch) == "struct VkDeviceMemoryReportCallbackDataEXT" {
3818		return true
3819	}
3820	// TODO(b/322902403): Make VkGetLatencyMarkerInfoNV work with berberis.
3821	if typе.Name(cpp_types.FirstArch) == "struct VkGetLatencyMarkerInfoNV" {
3822		return true
3823	}
3824	if typе.Name(cpp_types.FirstArch) == "struct VkLatencyTimingsFrameReportNV" {
3825		return true
3826	}
3827	// TODO(b/322902053): Make VkFaultCallbackInfo work with berberis.
3828	if typе.Name(cpp_types.FirstArch) == "struct VkFaultData" {
3829		return true
3830	}
3831	// TODO(b/322902400): Make VkDescriptorBufferBindingInfoEXT work with berberis.
3832	if typе.Name(cpp_types.FirstArch) == "struct VkDescriptorBufferBindingInfoEXT" {
3833		return true
3834	}
3835	// If structure is extensible then it may always be extended with incompatible extension via it's “pNext” field
3836	if isExtensibleType(typе) {
3837		return false
3838	}
3839	return cpp_types.IsInputCompatible(typе, host_arch, guest_arch)
3840}
3841
3842func isExtensibleType(typе cpp_types.Type) bool {
3843	if isPtrToAlias(typе) {
3844		return isExtensibleType(typе.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch))
3845	}
3846	if isPtrToConstAlias(typе) {
3847		return isExtensibleType(typе.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch))
3848	}
3849	if isPtrToStruct(typе) {
3850		return isExtensibleType(typе.Elem(cpp_types.FirstArch))
3851	}
3852	if isPtrToConstStruct(typе) {
3853		return isExtensibleType(typе.Elem(cpp_types.FirstArch).Elem(cpp_types.FirstArch))
3854	}
3855	if isStruct(typе) &&
3856		(typе.(vulkan_xml.ExtendedStructInfo).OptionalStruct() ||
3857			(typе.Field(0, cpp_types.FirstArch).Name() == "sType" && typе.Field(1, cpp_types.FirstArch).Name() == "pNext")) {
3858		return true
3859	}
3860	// Union or struct by itself may not be extensible, but it may include pointers to structs that are extensible, we have to check for that case, too.
3861	if isUnion(typе) || isStruct(typе) {
3862		ids := typе.NumField(cpp_types.FirstArch)
3863		for id := uint(0); id < ids; id++ {
3864			if isExtensibleType(typе.Field(id, cpp_types.FirstArch).Type()) {
3865				return true
3866			}
3867		}
3868	}
3869	return false
3870}
3871
3872func isAlias(typе cpp_types.Type) bool {
3873	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Alias})
3874}
3875
3876func isAliasOfEnum(typе cpp_types.Type) bool {
3877	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Alias, cpp_types.Enum})
3878}
3879
3880func isAliasOfOpaque(typе cpp_types.Type) bool {
3881	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Alias, cpp_types.Opaque})
3882}
3883
3884func isArray(typе cpp_types.Type) bool {
3885	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Array})
3886}
3887
3888func isConst(typе cpp_types.Type) bool {
3889	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Const})
3890}
3891
3892func isConstPtr(typе cpp_types.Type) bool {
3893	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Const, cpp_types.Ptr})
3894}
3895
3896func isConstPtrToFunc(typе cpp_types.Type) bool {
3897	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Const, cpp_types.Ptr, cpp_types.Func})
3898}
3899
3900func isEnum(typе cpp_types.Type) bool {
3901	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Enum})
3902}
3903
3904func isFunc(typе cpp_types.Type) bool {
3905	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Func})
3906}
3907
3908func isInt8T(typе cpp_types.Type) bool {
3909	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Int8T})
3910}
3911
3912func isInt16T(typе cpp_types.Type) bool {
3913	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Int16T})
3914}
3915
3916func isInt32T(typе cpp_types.Type) bool {
3917	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Int32T})
3918}
3919
3920func isInt64T(typе cpp_types.Type) bool {
3921	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Int64T})
3922}
3923
3924func isPtr(typе cpp_types.Type) bool {
3925	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr})
3926}
3927
3928func isPtrToAlias(typе cpp_types.Type) bool {
3929	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Alias})
3930}
3931
3932func isPtrToConstAlias(typе cpp_types.Type) bool {
3933	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Const, cpp_types.Alias})
3934}
3935
3936func isPtrToConst(typе cpp_types.Type) bool {
3937	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Const})
3938}
3939
3940func isPtrToConstOpaque(typе cpp_types.Type) bool {
3941	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Const, cpp_types.Opaque})
3942}
3943
3944func isPtrToConstStruct(typе cpp_types.Type) bool {
3945	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Const, cpp_types.Struct})
3946}
3947
3948func isPtrToFunc(typе cpp_types.Type) bool {
3949	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Func})
3950}
3951
3952func isPtrToOpaque(typе cpp_types.Type) bool {
3953	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Opaque})
3954}
3955
3956func isPtrToStruct(typе cpp_types.Type) bool {
3957	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Ptr, cpp_types.Struct})
3958}
3959
3960func isStruct(typе cpp_types.Type) bool {
3961	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Struct})
3962}
3963
3964func isUInt8T(typе cpp_types.Type) bool {
3965	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.UInt8T})
3966}
3967
3968func isUInt16T(typе cpp_types.Type) bool {
3969	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.UInt16T})
3970}
3971
3972func isUInt32T(typе cpp_types.Type) bool {
3973	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.UInt32T})
3974}
3975
3976func isUInt64T(typе cpp_types.Type) bool {
3977	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.UInt64T})
3978}
3979
3980func isUnion(typе cpp_types.Type) bool {
3981	return cpp_types.IsKind(typе, []cpp_types.Kind{cpp_types.Union})
3982}
3983
3984func toIntVal(b bool) int {
3985	if b {
3986		return 1
3987	} else {
3988		return 0
3989	}
3990}
3991