// Try process public static bool TryProcess(EnumSpec spec, VulkanSpec vkspec, Dictionary <string, EnumType> found, out EnumType?type) { type = null; // Check for alias type if (spec.Alias is not null) { if (!found.TryGetValue(spec.Alias.Name, out var alias)) { Program.PrintError($"Enum type '{spec.Name}' is aliased to unknown type '{spec.Alias.Name}'"); return(false); } // Return with alias type = new(spec, alias); return(true); } // Process entries List <Entry> entries = new(); foreach (var value in spec.Values) { // Process name if (NameHelper.ConvertEnumValue(spec.Name, value.Name) is not string procName) { Program.PrintError($"Failed to process enum value name '{value.Name}' for enum '{spec.Name}'"); return(false); } // Process value int procValue; if (value.ValueStr.StartsWith("0x")) { if (!Int32.TryParse(value.ValueStr.Substring("0x".Length), NumberStyles.AllowHexSpecifier, null, out procValue)) { Program.PrintError( $"Failed to parse hex value '{value.ValueStr}' for enum value '{value.Name}'"); return(false); } } else if (!Int32.TryParse(value.ValueStr, out procValue)) { Program.PrintError( $"Failed to parse decimal value '{value.ValueStr}' for enum value '{value.Name}'"); return(false); } if (value.IsBitpos) { procValue = 1 << procValue; } // Check for invalid duplicates (sometimes there are valid duplicates) var dup = entries.FirstOrDefault(ent => ent.Name == procName); if ((dup is not null) && (dup.Value != procValue)) { Program.PrintError($"Invalid duplicate enum value name '{procName}'"); return(false); } if (dup is null) { entries.Add(new(procName, procValue)); } } // Return type = new(spec, entries); return(true); }
// Generate struct types private static void GenerateStructs(Vendor vendor) { if (vendor.Structs.Count == 0) { return; } // Make path and file context var vpath = vendor.IsCore ? "Structs.cs" : Path.Combine(vendor.Tag, "Structs.cs"); using var file = new SourceFile(vpath); // For each struct List <string> ctorArgs = new(); List <string> ctorAssigns = new(); List <string> hashes = new(); List <string> comparisons = new(); foreach (var @struct in vendor.Structs.Values) { // Open block file.WriteLine($"[StructLayout(LayoutKind.{(@struct.IsUnion ? "Explicit" : "Sequential")})]"); using var block = file.PushBlock($"public unsafe partial struct {@struct.Name} : IEquatable<{@struct.Name}>"); // Typed structs if (@struct.IsTyped) { block.WriteLine($"public const VkStructureType TYPE = VkStructureType.{@struct.Type!};"); block.WriteLine(); } // Fields (and ctor arguments) ctorArgs.Clear(); ctorAssigns.Clear(); hashes.Clear(); comparisons.Clear(); foreach (var field in @struct.Fields) { var lower = NameHelper.GetSafeArgName(field.Name); if (field.ArraySize is not null) { if (field.IsFixed) { if (@struct.IsUnion) { block.WriteLine("[FieldOffset(0)]"); } block.WriteLine($"public fixed {field.Type} {field.Name}[{field.ArraySize}];"); for (uint i = 0; i < field.ArraySize; ++i) { ctorArgs.Add($"{field.Type} {lower}_{i} = default"); ctorAssigns.Add($"{field.Name}[{i}] = {lower}_{i};"); hashes.Add($"{field.Name}[{i}].GetHashCode()"); comparisons.Add($"(l.{field.Name}[{i}] == r.{field.Name}[{i}])"); } } else { for (uint i = 0; i < field.ArraySize; ++i) { block.WriteLine($"public {field.Type} {field.Name}_{i};"); ctorArgs.Add($"{field.Type} {lower}_{i} = default"); ctorAssigns.Add($"{field.Name}_{i} = {lower}_{i};"); hashes.Add($"{field.Name}_{i}.GetHashCode()"); comparisons.Add($"(l.{field.Name}_{i} == r.{field.Name}_{i})"); } } } else { if (@struct.IsUnion) { block.WriteLine("[FieldOffset(0)]"); } block.WriteLine($"public {field.Type} {field.Name};"); if (field.Name == "sType") { ctorAssigns.Add("sType = TYPE;"); } else if (field.Name == "pNext") { ctorAssigns.Add("pNext = null;"); } else { ctorArgs.Add($"{field.Type} {lower} = default"); ctorAssigns.Add($"{field.Name} = {lower};"); } var isPtr = field.Type.Contains('*'); hashes.Add(isPtr ? $"((ulong){field.Name}).GetHashCode()" : $"{field.Name}.GetHashCode()"); comparisons.Add($"(l.{field.Name} == r.{field.Name})"); } } block.WriteLine(); // Ctor if ([email protected] && ([email protected] || (@struct.Fields.Count > 2))) { block.WriteLine($"public {@struct.Name}("); for (int i = 0; i < ctorArgs.Count; ++i) { block.WriteLine($"\t{ctorArgs[i]}{((i == ctorArgs.Count - 1) ? "" : ",")}"); } block.WriteLine(") {"); foreach (var line in ctorAssigns) { block.WriteLine('\t' + line); } block.WriteLine("}"); block.WriteLine(); } else if (@struct.IsUnion) { foreach (var field in @struct.Fields) { var fname = NameHelper.GetSafeArgName(field.Name); if (field.ArraySize is not null) { block.WriteLine($"public {@struct.Name}("); for (uint i = 0; i < field.ArraySize; ++i) { block.WriteLine($"\tin {field.Type} {fname}_{i}{((i != field.ArraySize - 1) ? ", " : "")}"); } block.WriteLine(") {"); for (uint i = 0; i < field.ArraySize; ++i) { block.WriteLine('\t' + (field.IsFixed ? $"{field.Name}[{i}]" : $"{field.Name}_{i}") + $" = {fname}_{i};"); } block.WriteLine("}"); } else { block.WriteLine($"public {@struct.Name}(in {field.Type} {fname}) : this() => {field.Name} = {fname};"); } block.WriteLine(); } } // Equality block.WriteLine($"public readonly override bool Equals(object? o) => (o is {@struct.Name} s) && (this == s);"); block.WriteLine($"readonly bool IEquatable<{@struct.Name}>.Equals({@struct.Name} o) => o == this;"); block.WriteLine(); // Hash code block.WriteLine("[MethodImpl(MethodImplOptions.AggressiveOptimization)]"); using (var hash = block.PushBlock("public readonly override int GetHashCode()")) { hash.WriteLine("return"); for (int i = 0; i < hashes.Count; i += 4) { hash.WriteLine('\t' + (i != 0 ? "^ " : "") + String.Join(" ^ ", hashes.Skip(i).Take(4))); } hash.WriteLine("\t;"); } // Equality operators block.WriteLine("[MethodImpl(MethodImplOptions.AggressiveOptimization)]"); using (var op = block.PushBlock($"public static bool operator == (in {@struct.Name} l, in {@struct.Name} r)")) { op.WriteLine("return"); for (int i = 0; i < comparisons.Count; i += 4) { op.WriteLine('\t' + (i != 0 ? "&& " : "") + String.Join(" && ", comparisons.Skip(i).Take(4))); } op.WriteLine("\t;"); } block.WriteLine("[MethodImpl(MethodImplOptions.AggressiveOptimization)]"); using (var op = block.PushBlock($"public static bool operator != (in {@struct.Name} l, in {@struct.Name} r)")) { op.WriteLine("return"); for (int i = 0; i < comparisons.Count; i += 4) { op.WriteLine('\t' + (i != 0 ? "|| " : "") + String.Join(" || ", comparisons.Skip(i).Take(4).Select(cmp => cmp.Replace("==", "!=")))); } op.WriteLine("\t;"); } if ([email protected]) { // New function block.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]"); if (@struct.IsTyped) { block.WriteLine($"public static void New(out {@struct.Name} s) => s = new() {{ sType = TYPE }};"); } else { block.WriteLine($"public static void New(out {@struct.Name} s) => s = new();"); } } } }