Skip to content

Commit

Permalink
Add support for bitfields
Browse files Browse the repository at this point in the history
  • Loading branch information
Helco committed Jan 22, 2024
1 parent 3004ce3 commit 6d3a00f
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 13 deletions.
67 changes: 62 additions & 5 deletions src/CodeGenerator/ImguiDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ static int GetInt(JToken token, string key)
if (v == null) return 0;
return v.ToObject<int>();
}

static int? GetOptionalInt(JToken token, string key)
{
var v = token[key];
if (v == null) return null;
return v.ToObject<int>();
}

public void LoadFrom(string directory)
{

Expand Down Expand Up @@ -93,7 +101,9 @@ public void LoadFrom(string directory)
v["type"].ToString(),
GetInt(v, "size"),
v["template_type"]?.ToString(),
Enums);
Enums,
typeVariants: null,
GetOptionalInt(v, "bitfield"));
}).Where(tr => tr != null).ToArray();
return new TypeDefinition(name, fields);
}).Where(x => x != null).ToArray();
Expand Down Expand Up @@ -336,12 +346,34 @@ class TypeDefinition
{
public string Name { get; }
public TypeReference[] Fields { get; }
public BitField[] BitFields { get; }

public TypeDefinition(string name, TypeReference[] fields)
{
Name = name;
Fields = fields;

var bitFields = new List<BitField>();
int bitFieldStartI = -1;
for (int i = 0; i < fields.Length; i++)
{
if (fields[i].BitSize.HasValue && bitFieldStartI < 0)
bitFieldStartI = i;

if (!fields[i].BitSize.HasValue && bitFieldStartI >= 0)
{
bitFields.Add(new BitField(bitFields.Count, fields[bitFieldStartI..i]));
bitFieldStartI = -1;
}
}
if (bitFieldStartI >= 0)
bitFields.Add(new BitField(bitFields.Count, fields[bitFieldStartI..]));
BitFields = bitFields.ToArray();
}

public BitField GetBitFieldContaining(TypeReference field) =>
BitFields.FirstOrDefault(bitField => bitField.Fields.Contains(field))
?? throw new ArgumentException("Given is not part of any bit field");
}

class TypeReference
Expand All @@ -353,17 +385,18 @@ class TypeReference
public bool IsFunctionPointer { get; }
public string[] TypeVariants { get; }
public bool IsEnum { get; }
public int? BitSize { get; }

public TypeReference(string name, string type, int asize, EnumDefinition[] enums)
: this(name, type, asize, null, enums, null) { }
: this(name, type, asize, null, enums, null, null) { }

public TypeReference(string name, string type, int asize, EnumDefinition[] enums, string[] typeVariants)
: this(name, type, asize, null, enums, typeVariants) { }
: this(name, type, asize, null, enums, typeVariants, null) { }

public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums)
: this(name, type, asize, templateType, enums, null) { }
: this(name, type, asize, templateType, enums, null, null) { }

public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums, string[] typeVariants)
public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums, string[] typeVariants, int? bitSize)
{
Name = name;
Type = type.Replace("const", string.Empty).Trim();
Expand Down Expand Up @@ -410,6 +443,8 @@ public TypeReference(string name, string type, int asize, string templateType, E
TypeVariants = typeVariants;

IsEnum = enums.Any(t => t.Names.Contains(type) || t.FriendlyNames.Contains(type) || TypeInfo.WellKnownEnums.Contains(type));

BitSize = bitSize;
}

private int ParseSizeString(string sizePart, EnumDefinition[] enums)
Expand Down Expand Up @@ -453,6 +488,28 @@ public TypeReference WithVariant(int variantIndex, EnumDefinition[] enums)
}
}

class BitField
{
public string Name { get; }
public string Type { get; }
public TypeReference[] Fields { get; }

public BitField(int index, IEnumerable<TypeReference> fields)
{
Name = $"_bitField_{index}";
Fields = fields.ToArray();
Type = TypeInfo.GetTypeForBitfield(fields.Sum(f => f.BitSize.Value));
}

public int OffsetOf(TypeReference field)
{
var fieldIndex = Array.IndexOf(Fields, field);
if (fieldIndex < 0)
throw new ArgumentException("Given field is not part of the bit field");
return Fields.Take(fieldIndex).Sum(f => f.BitSize.Value);
}
}

class FunctionDefinition
{
public string Name { get; }
Expand Down
19 changes: 19 additions & 0 deletions src/CodeGenerator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ static void Main(string[] args)
}
}
}
else if (field.BitSize.HasValue)
{
var bitField = td.GetBitFieldContaining(field);
if (bitField.OffsetOf(field) > 0)
continue;

writer.WriteLine($"public {bitField.Type} {bitField.Name};");
}
else
{
writer.WriteLine($"public {typeStr} {field.Name};");
Expand Down Expand Up @@ -170,6 +178,17 @@ static void Main(string[] args)
string addrTarget = TypeInfo.LegalFixedTypes.Contains(rawType) ? $"NativePtr->{field.Name}" : $"&NativePtr->{field.Name}_0";
writer.WriteLine($"public RangeAccessor<{typeStr}> {field.Name} => new RangeAccessor<{typeStr}>({addrTarget}, {field.ArraySize});");
}
else if (field.BitSize.HasValue)
{
var bitField = td.GetBitFieldContaining(field);
var offset = bitField.OffsetOf(field);
var mask = (ulong)(1 << field.BitSize) - 1 << offset;

writer.PushBlock($"public {typeStr} {field.Name}");
writer.WriteLine($"get => ({typeStr})Util.GetBits(NativePtr->{bitField.Name}, {offset}, {field.BitSize});");
writer.WriteLine($"set => NativePtr->{bitField.Name} = Util.SetBits(NativePtr->{bitField.Name}, {offset}, {field.BitSize}, ({bitField.Type})value);");
writer.PopBlock();
}
else if (typeStr.Contains("ImVector"))
{
string vectorElementType = GetTypeString(field.TemplateType, false);
Expand Down
9 changes: 9 additions & 0 deletions src/CodeGenerator/TypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,14 @@ public class TypeInfo
"igInputTextMultiline",
"igInputTextWithHint"
};

public static string GetTypeForBitfield(int size) => size switch
{
_ when size <= 8 => "byte",
_ when size <= 16 => "ushort",
_ when size <= 32 => "uint",
_ when size <= 64 => "ulong",
_ => throw new System.NotSupportedException("Unsupported bitfield size: " + size)
};
}
}
22 changes: 16 additions & 6 deletions src/ImGui.NET/Generated/ImFontGlyph.gen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ namespace ImGuiNET
{
public unsafe partial struct ImFontGlyph
{
public uint Colored;
public uint Visible;
public uint Codepoint;
public uint _bitField_0;
public float AdvanceX;
public float X0;
public float Y0;
Expand All @@ -28,9 +26,21 @@ public unsafe partial struct ImFontGlyphPtr
public static implicit operator ImFontGlyphPtr(ImFontGlyph* nativePtr) => new ImFontGlyphPtr(nativePtr);
public static implicit operator ImFontGlyph* (ImFontGlyphPtr wrappedPtr) => wrappedPtr.NativePtr;
public static implicit operator ImFontGlyphPtr(IntPtr nativePtr) => new ImFontGlyphPtr(nativePtr);
public ref uint Colored => ref Unsafe.AsRef<uint>(&NativePtr->Colored);
public ref uint Visible => ref Unsafe.AsRef<uint>(&NativePtr->Visible);
public ref uint Codepoint => ref Unsafe.AsRef<uint>(&NativePtr->Codepoint);
public uint Colored
{
get => (uint)Util.GetBits(NativePtr->_bitField_0, 0, 1);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 0, 1, (uint)value);
}
public uint Visible
{
get => (uint)Util.GetBits(NativePtr->_bitField_0, 1, 1);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 1, 1, (uint)value);
}
public uint Codepoint
{
get => (uint)Util.GetBits(NativePtr->_bitField_0, 2, 30);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 2, 30, (uint)value);
}
public ref float AdvanceX => ref Unsafe.AsRef<float>(&NativePtr->AdvanceX);
public ref float X0 => ref Unsafe.AsRef<float>(&NativePtr->X0);
public ref float Y0 => ref Unsafe.AsRef<float>(&NativePtr->Y0);
Expand Down
8 changes: 6 additions & 2 deletions src/ImGui.NET/Generated/ImGuiTableColumnSortSpecs.gen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public unsafe partial struct ImGuiTableColumnSortSpecs
public uint ColumnUserID;
public short ColumnIndex;
public short SortOrder;
public ImGuiSortDirection SortDirection;
public byte _bitField_0;
}
public unsafe partial struct ImGuiTableColumnSortSpecsPtr
{
Expand All @@ -23,7 +23,11 @@ public unsafe partial struct ImGuiTableColumnSortSpecsPtr
public ref uint ColumnUserID => ref Unsafe.AsRef<uint>(&NativePtr->ColumnUserID);
public ref short ColumnIndex => ref Unsafe.AsRef<short>(&NativePtr->ColumnIndex);
public ref short SortOrder => ref Unsafe.AsRef<short>(&NativePtr->SortOrder);
public ref ImGuiSortDirection SortDirection => ref Unsafe.AsRef<ImGuiSortDirection>(&NativePtr->SortDirection);
public ImGuiSortDirection SortDirection
{
get => (ImGuiSortDirection)Util.GetBits(NativePtr->_bitField_0, 0, 8);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 0, 8, (byte)value);
}
public void Destroy()
{
ImGuiNative.ImGuiTableColumnSortSpecs_destroy((ImGuiTableColumnSortSpecs*)(NativePtr));
Expand Down
27 changes: 27 additions & 0 deletions src/ImGui.NET/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,32 @@ internal static int GetUtf8(string s, int start, int length, byte* utf8Bytes, in
return Encoding.UTF8.GetBytes(utf16Ptr + start, length, utf8Bytes, utf8ByteCount);
}
}

internal static byte SetBits(byte oldValue, int offset, int bitCount, byte newBits)
{
var mask = (byte)((1 << bitCount) - 1 << offset);
return (byte)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static ushort SetBits(ushort oldValue, int offset, int bitCount, ushort newBits)
{
var mask = (ushort)((1 << bitCount) - 1 << offset);
return (ushort)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static uint SetBits(uint oldValue, int offset, int bitCount, uint newBits)
{
var mask = (uint)((1 << bitCount) - 1 << offset);
return (uint)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static ulong SetBits(ulong oldValue, int offset, int bitCount, ulong newBits)
{
var mask = (ulong)((1 << bitCount) - 1 << offset);
return (ulong)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static ulong GetBits(ulong value, int offset, int bitCount) =>
(value >> offset) & (1UL << bitCount) - 1;
}
}

0 comments on commit 6d3a00f

Please sign in to comment.