Skip to content

Commit 8bf9e1f

Browse files
committed
Move Rank, ValueBitCount and ValueBitMask properties to Accessor to simplify PackedFieldDescriptor implementation
1 parent 38f1efc commit 8bf9e1f

4 files changed

Lines changed: 85 additions & 107 deletions

File tree

Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ internal abstract class PackedFieldAccessor
3030
/// </summary>
3131
protected Delegate NullableSetter;
3232

33+
public readonly int Rank;
34+
public readonly int ValueBitCount;
35+
protected readonly long ValueBitMask;
36+
3337
public void SetValue<T>(PackedTuple tuple, ref PackedFieldDescriptor descriptor, bool isNullable, T value)
3438
{
3539
var setter = (isNullable ? NullableSetter : Setter) as SetValueDelegate<T>;
@@ -65,6 +69,25 @@ public abstract bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor lef
6569
PackedTuple right, ref PackedFieldDescriptor rightDescriptor);
6670

6771
public abstract int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor);
72+
73+
protected PackedFieldAccessor(int rank)
74+
{
75+
Rank = rank;
76+
ValueBitCount = 1 << Rank;
77+
78+
// What we want here is to shift 1L by ValueBitCount to left and then subtract 1
79+
// This gives us a mask. For example if bit count = 4 then
80+
// 0000_0001 << 4 = 0001_0000
81+
// 0001_000 - 1 = 0000_1111
82+
// However in case bit count equal to data type size left shift doesn't work as we want
83+
// e.g. for Int8 : 0000_0001 << 8 = 0000_0001 but we would like it to be 0000_0000
84+
// because 0000_0000 - 1 = 1111_1111 and this is exactly what we need.
85+
// As a workaround we do left shift in two steps. In the example above
86+
// 0000_0001 << 7 = 1000_0000
87+
// and then
88+
// 1000_0000 << 1 = 0000_0000
89+
ValueBitMask = (1L << (ValueBitCount - 1) << 1) - 1;
90+
}
6891
}
6992

7093
internal sealed class ObjectFieldAccessor : PackedFieldAccessor
@@ -73,12 +96,12 @@ public override object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescrip
7396
{
7497
var state = tuple.GetFieldState(ref descriptor);
7598
fieldState = state;
76-
return state==TupleFieldState.Available ? tuple.Objects[descriptor.ValueIndex] : null;
99+
return state==TupleFieldState.Available ? tuple.Objects[descriptor.ObjectIndex] : null;
77100
}
78101

79102
public override void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, object value)
80103
{
81-
tuple.Objects[descriptor.ValueIndex] = value;
104+
tuple.Objects[descriptor.ObjectIndex] = value;
82105
if (value!=null)
83106
tuple.SetFieldState(ref descriptor, TupleFieldState.Available);
84107
else
@@ -88,27 +111,29 @@ public override void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescripto
88111
public override void CopyValue(PackedTuple source, ref PackedFieldDescriptor sourceDescriptor,
89112
PackedTuple target, ref PackedFieldDescriptor targetDescriptor)
90113
{
91-
target.Objects[targetDescriptor.ValueIndex] = source.Objects[sourceDescriptor.ValueIndex];
114+
target.Objects[targetDescriptor.ObjectIndex] = source.Objects[sourceDescriptor.ObjectIndex];
92115
}
93116

94117
public override bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor leftDescriptor,
95118
PackedTuple right, ref PackedFieldDescriptor rightDescriptor)
96119
{
97-
var leftValue = left.Objects[leftDescriptor.ValueIndex];
98-
var rightValue = right.Objects[rightDescriptor.ValueIndex];
120+
var leftValue = left.Objects[leftDescriptor.ObjectIndex];
121+
var rightValue = right.Objects[rightDescriptor.ObjectIndex];
99122
return leftValue.Equals(rightValue);
100123
}
101124

102125
public override int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor)
103126
{
104-
return tuple.Objects[descriptor.ValueIndex].GetHashCode();
127+
return tuple.Objects[descriptor.ObjectIndex].GetHashCode();
105128
}
129+
130+
public ObjectFieldAccessor()
131+
: base(-1)
132+
{ }
106133
}
107134

108135
internal abstract class ValueFieldAccessor : PackedFieldAccessor
109136
{
110-
public readonly int Rank;
111-
112137
public Type FieldType { get; protected set; }
113138

114139
private static int GetRank(int bitSize)
@@ -122,9 +147,8 @@ private static int GetRank(int bitSize)
122147
}
123148

124149
protected ValueFieldAccessor(int bitCount)
125-
{
126-
Rank = GetRank(bitCount);
127-
}
150+
: base(GetRank(bitCount))
151+
{}
128152
}
129153

130154
internal abstract class ValueFieldAccessor<T> : ValueFieldAccessor
@@ -217,7 +241,7 @@ private void Store(PackedTuple tuple, ref PackedFieldDescriptor d, T value)
217241

218242
var encoded = Encode(value);
219243
var block = tuple.Values[d.ValueIndex];
220-
var mask = d.ValueBitMask << d.ValueBitOffset;
244+
var mask = ValueBitMask << d.ValueBitOffset;
221245
tuple.Values[d.ValueIndex] = (block & ~mask) | ((encoded << d.ValueBitOffset) & mask);
222246
}
223247

@@ -227,7 +251,7 @@ private T Load(PackedTuple tuple, ref PackedFieldDescriptor d)
227251
return Decode(tuple.Values, d.ValueIndex);
228252
}
229253

230-
var encoded = (tuple.Values[d.ValueIndex] >> d.ValueBitOffset) & d.ValueBitMask;
254+
var encoded = (tuple.Values[d.ValueIndex] >> d.ValueBitOffset) & ValueBitMask;
231255
return Decode(encoded);
232256
}
233257

Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,76 +5,42 @@
55
// Created: 2012.12.29
66

77
using System;
8+
using System.Runtime.CompilerServices;
89

910
namespace Xtensive.Tuples.Packed
1011
{
1112
[Serializable]
1213
internal struct PackedFieldDescriptor
1314
{
14-
private const int IndexBitCount = 20;
15-
private const int IndexMask = (1 << IndexBitCount) - 1;
16-
private const int OffsetBitCount = 7;
17-
private const int OffsetMask = ((1 << OffsetBitCount) - 1) << IndexBitCount;
15+
private const int OffsetBitCount = 6;
16+
private const int OffsetMask = (1 << OffsetBitCount) - 1;
1817

19-
private const int MaskBitCount = (sizeof(int) * 8) - (IndexBitCount + OffsetBitCount);
20-
private const int GetValueMask = (1 << MaskBitCount) - 1;
21-
private const int SetValueMask = GetValueMask << (IndexBitCount + OffsetBitCount);
22-
23-
private int data1;
24-
private int data2;
18+
private int indexField;
19+
private int stateField;
2520

2621
[NonSerialized]
2722
public PackedFieldAccessor Accessor;
2823

29-
public int ValueIndex
30-
{
31-
get => data1 & IndexMask;
32-
set => data1 = (data1 & ~IndexMask) | (value & IndexMask);
33-
}
24+
public bool IsObjectField => Accessor.Rank < 0;
3425

35-
public int ValueBitOffset
26+
public int ObjectIndex
3627
{
37-
get => (data1 & OffsetMask) >> IndexBitCount;
38-
set => data1 = (data1 & ~OffsetMask) | ((value << IndexBitCount) & OffsetMask);
28+
get => indexField;
29+
set => indexField = value;
3930
}
4031

41-
public int Rank
42-
{
43-
get => (data1 >> (IndexBitCount + OffsetBitCount)) & GetValueMask;
44-
set => data1 = (data1 & ~SetValueMask) | ((value << (IndexBitCount + OffsetBitCount)) & SetValueMask);
45-
}
32+
public int ValueIndex => indexField >> OffsetBitCount;
33+
public int ValueBitOffset => indexField & OffsetMask;
4634

47-
public int ValueBitCount => 1 << Rank;
35+
public int StateIndex => stateField >> OffsetBitCount;
36+
public int StateBitOffset => stateField & OffsetMask;
4837

49-
// What we want here is to shift 1L by ValueBitCount to left and then subtract 1
50-
// This gives us a mask. For example if bit count = 4 then
51-
// 0000_0001 << 4 = 0001_0000
52-
// 0001_000 - 1 = 0000_1111
53-
// However in case bit count equal to data type size left shift doesn't work as we want
54-
// e.g. for Int8 : 0000_0001 << 8 = 0000_0001 but we would like it to be 0000_0000
55-
// because 0000_0000 - 1 = 1111_1111 and this is exactly what we need.
56-
// As a workaround we do left shift in two steps. In the example above
57-
// 0000_0001 << 7 = 1000_0000
58-
// and then
59-
// 1000_0000 << 1 = 0000_0000
60-
public long ValueBitMask => (1L << (ValueBitCount - 1) << 1) - 1;
38+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
39+
public void SetValueBitOffset(int totalBitOffset)
40+
=> indexField = totalBitOffset;
6141

62-
public int StateIndex
63-
{
64-
get => data2 & IndexMask;
65-
set => data2 = (data2 & ~IndexMask) | (value & IndexMask);
66-
}
67-
68-
public int StateBitOffset
69-
{
70-
get => (data2 & OffsetMask) >> IndexBitCount;
71-
set => data2 = (data2 & ~OffsetMask) | ((value << IndexBitCount) & OffsetMask);
72-
}
73-
74-
public FieldPackingType PackingType
75-
{
76-
get => (FieldPackingType)((data2 >> (IndexBitCount + OffsetBitCount)) & GetValueMask);
77-
set => data2 = (data2 & ~SetValueMask) | (((int)value << (IndexBitCount + OffsetBitCount)) & SetValueMask);
78-
}
42+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
43+
public void SetStateTotalBitOffset(int stateBitOffset)
44+
=> stateField = stateBitOffset;
7945
}
8046
}

Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ public void SetFieldState(ref PackedFieldDescriptor d, TupleFieldState fieldStat
108108
var block = Values[d.StateIndex];
109109
Values[d.StateIndex] = (block & ~(3L << d.StateBitOffset)) | (bits << d.StateBitOffset);
110110

111-
if (fieldState!=TupleFieldState.Available && d.PackingType==FieldPackingType.Object) {
112-
Objects[d.ValueIndex] = null;
111+
if (fieldState!=TupleFieldState.Available && d.IsObjectField) {
112+
Objects[d.ObjectIndex] = null;
113113
}
114114
}
115115

Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2003-2012 Xtensive LLC.
1+
// Copyright (C) 2003-2012 Xtensive LLC.
22
// All rights reserved.
33
// For conditions of distribution and use, see license.
44
// Created by: Denis Krjuchkov
@@ -163,12 +163,9 @@ public static void ConfigureLen1(Type[] fieldTypes, ref PackedFieldDescriptor de
163163
var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[0]);
164164
if (valueAccessor != null) {
165165
descriptor.Accessor = valueAccessor;
166-
descriptor.PackingType = FieldPackingType.Value;
167-
descriptor.Rank = valueAccessor.Rank;
168-
descriptor.ValueIndex = 1;
166+
descriptor.SetValueBitOffset(Val064BitCount);
169167

170-
var valBitCount = 1 << valueAccessor.Rank;
171-
valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank);
168+
valuesLength = ((1 << valueAccessor.Rank) + ((Val064BitCount * 2) - 1)) >> Val064Rank;
172169
objectsLength = 0;
173170
fieldTypes[0] = valueAccessor.FieldType;
174171
return;
@@ -186,41 +183,36 @@ public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor de
186183
ConfigureFieldPhase1(ref descriptor1, ref valCounters, fieldTypes, 0);
187184
ConfigureFieldPhase1(ref descriptor2, ref valCounters, fieldTypes, 1);
188185
objectsLength = valCounters.ObjectCounter;
189-
int valBitCount;
186+
int val1BitCount, val2BitCount;
190187
switch (objectsLength) {
191188
case 2:
192189
valuesLength = 1;
193190
return;
194191
case 1: {
195-
if (descriptor2.PackingType == FieldPackingType.Value) {
196-
descriptor2.ValueIndex = 1;
197-
valBitCount = 1 << descriptor2.Rank;
192+
if (descriptor1.IsObjectField) {
193+
descriptor2.SetValueBitOffset(Val064BitCount);
194+
val1BitCount = descriptor2.Accessor.ValueBitCount;
198195
}
199196
else {
200-
descriptor1.ValueIndex = 1;
201-
valBitCount = 1 << descriptor1.Rank;
197+
descriptor1.SetValueBitOffset(Val064BitCount);
198+
val1BitCount = descriptor1.Accessor.ValueBitCount;
202199
}
203-
valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank);
200+
valuesLength = 1 + ((val1BitCount + (Val064BitCount - 1)) >> Val064Rank);
204201
return;
205202
}
206203
}
207204
// Both descriptors are value descriptors
208-
int rank1 = descriptor1.Rank, rank2 = descriptor2.Rank;
209-
if (rank2 > rank1) {
210-
descriptor2.ValueIndex = 1;
211-
valBitCount = 1 << rank2;
212-
descriptor1.ValueIndex = 1 + (valBitCount >> Val064Rank);
213-
descriptor1.ValueBitOffset = valBitCount & Modulo064RemainderMask;
214-
valBitCount += 1 << rank1;
205+
val1BitCount = descriptor1.Accessor.ValueBitCount;
206+
val2BitCount = descriptor2.Accessor.ValueBitCount;
207+
if (val2BitCount > val1BitCount) {
208+
descriptor2.SetValueBitOffset(Val064BitCount);
209+
descriptor1.SetValueBitOffset(Val064BitCount + val2BitCount);
215210
}
216211
else {
217-
descriptor1.ValueIndex = 1;
218-
valBitCount = 1 << rank1;
219-
descriptor2.ValueIndex = 1 + (valBitCount >> Val064Rank);
220-
descriptor2.ValueBitOffset = valBitCount & Modulo064RemainderMask;
221-
valBitCount += 1 << rank2;
212+
descriptor1.SetValueBitOffset(Val064BitCount);
213+
descriptor2.SetValueBitOffset(Val064BitCount + val1BitCount);
222214
}
223-
valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank);
215+
valuesLength = (val1BitCount + val2BitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank;
224216
}
225217

226218
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -269,26 +261,22 @@ private static void InitValPointer(ref ValPointer pointer, ref ValPointer prevPo
269261
[MethodImpl(MethodImplOptions.AggressiveInlining)]
270262
private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref ValPointer valPointer)
271263
{
272-
descriptor.ValueIndex = valPointer.Index;
273-
descriptor.ValueBitOffset = valPointer.Offset;
274-
275-
var increasedOffset = valPointer.Offset + descriptor.ValueBitCount;
276-
valPointer.Index += increasedOffset >> Val064Rank;
277-
valPointer.Offset = increasedOffset & Modulo064RemainderMask;
264+
var totalBitCount = (valPointer.Index << Val064Rank) + valPointer.Offset;
265+
descriptor.SetValueBitOffset(totalBitCount);
266+
totalBitCount += descriptor.Accessor.ValueBitCount;
267+
valPointer.Index = totalBitCount >> Val064Rank;
268+
valPointer.Offset = totalBitCount & Modulo064RemainderMask;
278269
}
279270

280271
[MethodImpl(MethodImplOptions.AggressiveInlining)]
281272
private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, ref ValCounters counters,
282273
Type[] fieldTypes, int fieldIndex)
283274
{
284-
descriptor.StateIndex = fieldIndex >> Val032Rank; // d.FieldIndex / 32
285-
descriptor.StateBitOffset = (fieldIndex & Modulo032RemainderMask) << 1;
275+
descriptor.SetStateTotalBitOffset(fieldIndex << 1);
286276

287277
var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[fieldIndex]);
288278
if (valueAccessor != null) {
289279
descriptor.Accessor = valueAccessor;
290-
descriptor.PackingType = FieldPackingType.Value;
291-
descriptor.Rank = valueAccessor.Rank;
292280

293281
IncrementerByRank[valueAccessor.Rank].Invoke(ref counters);
294282

@@ -297,18 +285,18 @@ private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, r
297285
}
298286

299287
descriptor.Accessor = ObjectAccessor;
300-
descriptor.ValueIndex = counters.ObjectCounter++;
288+
descriptor.ObjectIndex = counters.ObjectCounter++;
301289
}
302290

303291
[MethodImpl(MethodImplOptions.AggressiveInlining)]
304292
private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers)
305293
{
306-
if (descriptor.PackingType == FieldPackingType.Object) {
294+
if (descriptor.IsObjectField) {
307295
return;
308296
}
309297

310298
// d.PackingType == FieldPackingType.Value
311-
PositionUpdaterByRank[descriptor.Rank].Invoke(ref descriptor, ref valPointers);
299+
PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref valPointers);
312300
}
313301

314302
static TupleLayout()

0 commit comments

Comments
 (0)