// Generate bitmask types private static void GenerateBitmasks(Vendor vendor) { if (vendor.Bitmasks.Count == 0) { return; } // Make path and file context var vpath = vendor.IsCore ? "Bitmasks.cs" : Path.Combine(vendor.Tag, "Bitmasks.cs"); using var file = new SourceFile(vpath); // For each bitmask foreach (var type in vendor.Bitmasks.Values) { // Open block file.WriteLine("[Flags]"); using var block = file.PushBlock($"public enum {type.Name} : uint"); // Write values foreach (var entry in type.Entries) { block.WriteLine($"{entry.Name} = {entry.Value},"); } } }
public SourceBlock PushBlock(string?header) { if (header is not null) { File.WriteLine(header); } File.WriteLine("{"); File.PushBlock(Depth); return(new(File)); }
// 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();"); } } } }