Skip to content

Commit 02fdc70

Browse files
Copilotdadhi
andauthored
Split ExprNode header into explicit fields
Agent-Logs-Url: https://github.com/dadhi/FastExpressionCompiler/sessions/9f8351be-178c-4a11-ad10-ad59e1688680 Co-authored-by: dadhi <39516+dadhi@users.noreply.github.com>
1 parent d90ce7e commit 02fdc70

1 file changed

Lines changed: 30 additions & 43 deletions

File tree

src/FastExpressionCompiler.LightExpression/FlatExpression.cs

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,9 @@ public enum ExprNodeKind : byte
5555
[StructLayout(LayoutKind.Explicit, Size = 24)]
5656
public struct ExprNode
5757
{
58-
// Packed layout of `_data` (MSB -> LSB):
59-
// [ 8 bits NodeType ][ 8 bits Tag(flags+kind) ][ 16 bits NextIdx ][ 16 bits ChildCount ][ 16 bits ChildIdx ]
60-
private const int NodeTypeShift = 56;
61-
private const int TagShift = 48;
62-
private const int NextShift = 32;
63-
private const int CountShift = 16;
64-
private const ulong IndexMask = 0xFFFF;
65-
private const ulong KindMask = 0x0F;
58+
private const byte KindMask = 0x0F;
6659
private const byte NextReservedFlag = 0x4;
6760
private const byte NextPointsParentFlag = 0x8;
68-
private const ulong TagMask = 0xFFUL << TagShift;
69-
private const ulong NextMask = IndexMask << NextShift;
70-
private const ulong ChildCountMask = IndexMask << CountShift;
71-
private const ulong ChildInfoMask = ChildCountMask | IndexMask;
72-
private const ulong KeepWithoutNextMask = ~NextMask;
73-
private const ulong KeepWithoutChildInfoMask = ~ChildInfoMask;
7461
private const int FlagsShift = 4;
7562

7663
/// <summary>Gets or sets the runtime type of the represented node.</summary>
@@ -81,66 +68,68 @@ public struct ExprNode
8168
[FieldOffset(8)]
8269
public object Obj;
8370
[FieldOffset(16)]
84-
private ulong _data;
71+
private ushort _childIdx;
72+
[FieldOffset(18)]
73+
private ushort _childCount;
74+
[FieldOffset(20)]
75+
private ushort _nextIdx;
76+
[FieldOffset(22)]
77+
private byte _tag;
78+
[FieldOffset(23)]
79+
private byte _nodeType;
8580

8681
/// <summary>Gets the expression kind encoded for this node.</summary>
87-
// Extracts bits [63..56].
88-
public ExpressionType NodeType => (ExpressionType)((_data >> NodeTypeShift) & 0xFF);
82+
public ExpressionType NodeType => (ExpressionType)_nodeType;
8983

9084
/// <summary>Gets the payload classification for this node.</summary>
91-
// Extracts low 4 bits from Tag [51..48].
92-
public ExprNodeKind Kind => (ExprNodeKind)((_data >> TagShift) & KindMask);
85+
public ExprNodeKind Kind => (ExprNodeKind)(_tag & KindMask);
9386

94-
// Extracts high 4 bits from Tag [55..52].
95-
internal byte Flags => (byte)(((byte)(_data >> TagShift)) >> FlagsShift);
87+
internal byte Flags => (byte)(_tag >> FlagsShift);
9688

9789
/// <summary>Gets the next sibling node index in the intrusive child chain.</summary>
98-
public int NextIdx => (int)((_data >> NextShift) & IndexMask);
90+
public int NextIdx => _nextIdx;
9991

10092
internal bool IsParentLink => (Flags & NextPointsParentFlag) != 0;
10193

102-
internal bool HasNextLink => (_data & NextMask) != 0 || (Flags & (NextPointsParentFlag | NextReservedFlag)) != 0;
94+
internal bool HasNextLink => _nextIdx != 0 || (Flags & (NextPointsParentFlag | NextReservedFlag)) != 0;
10395

10496
/// <summary>Gets the number of direct children linked from this node.</summary>
105-
public int ChildCount => (int)((_data >> CountShift) & IndexMask);
97+
public int ChildCount => _childCount;
10698

10799
/// <summary>Gets the first child index or an auxiliary payload index.</summary>
108-
public int ChildIdx => (int)(_data & IndexMask);
100+
public int ChildIdx => _childIdx;
109101

110102
internal ExprNode(Type type, object obj, ExpressionType nodeType, ExprNodeKind kind, byte flags = 0, int childIdx = 0, int childCount = 0, int nextIdx = 0)
111103
{
112104
Type = type;
113105
Obj = obj;
114-
var tag = (byte)((flags << FlagsShift) | (byte)kind);
115-
_data = ((ulong)(byte)nodeType << NodeTypeShift)
116-
| ((ulong)tag << TagShift)
117-
| ((ulong)(ushort)nextIdx << NextShift)
118-
| ((ulong)(ushort)childCount << CountShift)
119-
| (ushort)childIdx;
106+
_childIdx = (ushort)childIdx;
107+
_childCount = (ushort)childCount;
108+
_nextIdx = (ushort)nextIdx;
109+
_tag = (byte)((flags << FlagsShift) | (byte)kind);
110+
_nodeType = (byte)nodeType;
120111
}
121112

122113
[MethodImpl(MethodImplOptions.AggressiveInlining)]
123114
internal void SetNextSiblingIdx(int nextIdx)
124115
{
125-
// Replace NextIdx [47..32] and clear link-state flags to "regular sibling link".
126-
_data = (_data & KeepWithoutNextMask) | ((ulong)(ushort)nextIdx << NextShift);
116+
_nextIdx = (ushort)nextIdx;
127117
SetFlags((byte)(Flags & ~(NextPointsParentFlag | NextReservedFlag)));
128118
}
129119

130120
[MethodImpl(MethodImplOptions.AggressiveInlining)]
131121
internal void SetParentIdx(int parentIdx)
132122
{
133-
// Replace NextIdx [47..32] and mark it as "points to parent" (not sibling).
134-
_data = (_data & KeepWithoutNextMask) | ((ulong)(ushort)parentIdx << NextShift);
123+
_nextIdx = (ushort)parentIdx;
135124
SetFlags((byte)((Flags | NextPointsParentFlag) & ~NextReservedFlag));
136125
}
137126

138127
[MethodImpl(MethodImplOptions.AggressiveInlining)]
139-
internal void SetChildInfo(int childIdx, int childCount) =>
140-
// Replace ChildCount [31..16] and ChildIdx [15..0] together as one logical payload.
141-
_data = (_data & KeepWithoutChildInfoMask)
142-
| ((ulong)(ushort)childCount << CountShift)
143-
| (ushort)childIdx;
128+
internal void SetChildInfo(int childIdx, int childCount)
129+
{
130+
_childIdx = (ushort)childIdx;
131+
_childCount = (ushort)childCount;
132+
}
144133

145134
[MethodImpl(MethodImplOptions.AggressiveInlining)]
146135
internal bool Is(ExprNodeKind kind) => Kind == kind;
@@ -160,9 +149,7 @@ internal bool IsExpression() =>
160149
[MethodImpl(MethodImplOptions.AggressiveInlining)]
161150
private void SetFlags(byte flags)
162151
{
163-
// Rebuild Tag [55..48] as [flags(4 bits) | kind(4 bits)] and replace in place.
164-
var tag = (byte)((flags << FlagsShift) | (byte)Kind);
165-
_data = (_data & ~TagMask) | ((ulong)tag << TagShift);
152+
_tag = (byte)((flags << FlagsShift) | (byte)Kind);
166153
}
167154
}
168155

0 commit comments

Comments
 (0)