예제 #1
0
파일: EnumType.cs 프로젝트: LibVega/VVK
        // 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);
        }
예제 #2
0
        // 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();");
                    }
                }
            }
        }