Skip to content

Commit a6b9352

Browse files
committed
Use ref readonly to optimize PackedFieldDescriptor copying
1 parent f9d4d0f commit a6b9352

File tree

3 files changed

+72
-77
lines changed

3 files changed

+72
-77
lines changed

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

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ namespace Xtensive.Tuples.Packed
1111
[Serializable]
1212
internal sealed class PackedTuple : RegularTuple
1313
{
14-
private static readonly object[] EmptyObjectArray = new object[0];
15-
1614
public readonly TupleDescriptor PackedDescriptor;
1715
public readonly long[] Values;
1816
public readonly object[] Objects;
@@ -35,24 +33,26 @@ public override Tuple CreateNew()
3533
public override bool Equals(Tuple other)
3634
{
3735
var packedOther = other as PackedTuple;
38-
if (packedOther==null)
36+
if (packedOther == null)
3937
return base.Equals(other);
4038

4139
if (ReferenceEquals(packedOther, this))
4240
return true;
43-
if (Descriptor!=packedOther.Descriptor)
41+
if (Descriptor != packedOther.Descriptor)
4442
return false;
4543

4644
var fieldDescriptors = PackedDescriptor.FieldDescriptors;
4745
var count = Count;
4846
for (int i = 0; i < count; i++) {
49-
ref var descriptor = ref fieldDescriptors[i];
47+
ref readonly var descriptor = ref fieldDescriptors[i];
5048
var thisState = GetFieldState(descriptor);
5149
var otherState = packedOther.GetFieldState(descriptor);
52-
if (thisState!=otherState)
50+
if (thisState != otherState) {
5351
return false;
54-
if (thisState!=TupleFieldState.Available)
52+
}
53+
if (thisState != TupleFieldState.Available) {
5554
continue;
55+
}
5656
var accessor = descriptor.Accessor;
5757
if (!accessor.ValueEquals(this, descriptor, packedOther, descriptor))
5858
return false;
@@ -67,7 +67,7 @@ public override int GetHashCode()
6767
var fieldDescriptors = PackedDescriptor.FieldDescriptors;
6868
int result = 0;
6969
for (int i = 0; i < count; i++) {
70-
ref var descriptor = ref fieldDescriptors[i];
70+
ref readonly var descriptor = ref fieldDescriptors[i];
7171
var state = GetFieldState(descriptor);
7272
var fieldHash = state == TupleFieldState.Available
7373
? descriptor.Accessor.GetValueHashCode(this, descriptor)
@@ -77,14 +77,12 @@ public override int GetHashCode()
7777
return result;
7878
}
7979

80-
public override TupleFieldState GetFieldState(int fieldIndex)
81-
{
82-
return GetFieldState(PackedDescriptor.FieldDescriptors[fieldIndex]);
83-
}
80+
public override TupleFieldState GetFieldState(int fieldIndex) =>
81+
GetFieldState(PackedDescriptor.FieldDescriptors[fieldIndex]);
8482

8583
protected internal override void SetFieldState(int fieldIndex, TupleFieldState fieldState)
8684
{
87-
if (fieldState==TupleFieldState.Null) {
85+
if (fieldState == TupleFieldState.Null) {
8886
throw new ArgumentOutOfRangeException(nameof(fieldState));
8987
}
9088

@@ -93,13 +91,13 @@ protected internal override void SetFieldState(int fieldIndex, TupleFieldState f
9391

9492
public override object GetValue(int fieldIndex, out TupleFieldState fieldState)
9593
{
96-
ref var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
94+
ref readonly var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
9795
return descriptor.Accessor.GetUntypedValue(this, descriptor, out fieldState);
9896
}
9997

10098
public override void SetValue(int fieldIndex, object fieldValue)
10199
{
102-
ref var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
100+
ref readonly var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
103101
descriptor.Accessor.SetUntypedValue(this, descriptor, fieldValue);
104102
}
105103

@@ -109,7 +107,7 @@ public void SetFieldState(in PackedFieldDescriptor d, TupleFieldState fieldState
109107
ref var block = ref Values[d.StateIndex];
110108
block = (block & ~(3L << d.StateBitOffset)) | (bits << d.StateBitOffset);
111109

112-
if (fieldState!=TupleFieldState.Available && d.IsObjectField) {
110+
if (fieldState != TupleFieldState.Available && d.IsObjectField) {
113111
Objects[d.ObjectIndex] = null;
114112
}
115113
}
@@ -127,7 +125,7 @@ public PackedTuple(TupleDescriptor descriptor)
127125
Values = new long[PackedDescriptor.ValuesLength];
128126
Objects = PackedDescriptor.ObjectsLength > 0
129127
? new object[PackedDescriptor.ObjectsLength]
130-
: EmptyObjectArray;
128+
: Array.Empty<object>();
131129
}
132130

133131
private PackedTuple(PackedTuple origin)
@@ -137,7 +135,7 @@ private PackedTuple(PackedTuple origin)
137135
Values = (long[]) origin.Values.Clone();
138136
Objects = PackedDescriptor.ObjectsLength > 0
139137
? (object[]) origin.Objects.Clone()
140-
: EmptyObjectArray;
138+
: Array.Empty<object>();
141139
}
142140
}
143141
}

Orm/Xtensive.Orm/Tuples/Tuple.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,13 @@ public T GetValue<T>(int fieldIndex, out TupleFieldState fieldState)
111111
var isNullable = null==default(T); // Is nullable value type or class
112112

113113
if (this is PackedTuple packedTuple) {
114-
ref var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex];
114+
ref readonly var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex];
115115
return descriptor.Accessor.GetValue<T>(packedTuple, descriptor, isNullable, out fieldState);
116116
}
117117

118118
var mappedContainer = GetMappedContainer(fieldIndex, false);
119119
if (mappedContainer.First is PackedTuple mappedTuple) {
120-
ref var descriptor = ref mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second];
120+
ref readonly var descriptor = ref mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second];
121121
return descriptor.Accessor.GetValue<T>(mappedTuple, descriptor, isNullable, out fieldState);
122122
}
123123

@@ -186,14 +186,14 @@ public void SetValue<T>(int fieldIndex, T fieldValue)
186186
var isNullable = null==default(T); // Is nullable value type or class
187187

188188
if (this is PackedTuple packedTuple) {
189-
ref var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex];
189+
ref readonly var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex];
190190
descriptor.Accessor.SetValue(packedTuple, descriptor, isNullable, fieldValue);
191191
return;
192192
}
193193

194194
var mappedContainer = GetMappedContainer(fieldIndex, true);
195195
if (mappedContainer.First is PackedTuple mappedTuple) {
196-
ref var descriptor = ref mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second];
196+
ref readonly var descriptor = ref mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second];
197197
descriptor.Accessor.SetValue(mappedTuple, descriptor, isNullable, fieldValue);
198198
return;
199199
}

Orm/Xtensive.Orm/Tuples/TupleExtensions.cs

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,12 @@ public static void CopyTo(this Tuple source, Tuple target)
9696
/// Negative value in this map means "skip this element".</param>
9797
public static void CopyTo(this Tuple source, Tuple target, IReadOnlyList<int> map)
9898
{
99-
var packedSource = source as PackedTuple;
100-
var packedTarget = target as PackedTuple;
101-
102-
if (packedSource!=null && packedTarget!=null)
99+
if (source is PackedTuple packedSource && target is PackedTuple packedTarget) {
103100
CopyTupleWithMappingFast(packedSource, packedTarget, map);
104-
else
101+
}
102+
else {
105103
CopyTupleWithMappingSlow(source, target, map);
104+
}
106105
}
107106

108107
/// <summary>
@@ -120,20 +119,18 @@ public static void CopyTo(this Tuple[] sources, Tuple target, Pair<int, int>[] m
120119
var packedSources = new PackedTuple[sources.Length];
121120

122121
for (int i = 0; i < sources.Length; i++) {
123-
var packedSource = sources[i] as PackedTuple;
124-
if (packedSource==null) {
122+
if (sources[i] is PackedTuple packedSource) {
123+
packedSources[i] = packedSource;
124+
}
125+
else {
125126
haveSlowSource = true;
126127
break;
127128
}
128-
packedSources[i] = packedSource;
129129
}
130130

131-
if (!haveSlowSource) {
132-
var packedTarget = target as PackedTuple;
133-
if (packedTarget!=null) {
134-
CopyTupleArrayWithMappingFast(packedSources, packedTarget, map);
135-
return;
136-
}
131+
if (!haveSlowSource && target is PackedTuple packedTarget) {
132+
CopyTupleArrayWithMappingFast(packedSources, packedTarget, map);
133+
return;
137134
}
138135

139136
CopyTupleArrayWithMappingSlow(sources, target, map);
@@ -154,20 +151,18 @@ public static void CopyTo(this FixedList3<Tuple> sources, Tuple target, Pair<int
154151
var packedSources = new FixedList3<PackedTuple>();
155152

156153
for (int i = 0; i < sources.Count; i++) {
157-
var packedSource = sources[i] as PackedTuple;
158-
if (packedSource==null) {
154+
if (sources[i] is PackedTuple packedSource) {
155+
packedSources.Push(packedSource);
156+
}
157+
else {
159158
haveSlowSource = true;
160159
break;
161160
}
162-
packedSources.Push(packedSource);
163161
}
164162

165-
if (!haveSlowSource) {
166-
var packedTarget = target as PackedTuple;
167-
if (packedTarget!=null) {
168-
Copy3TuplesWithMappingFast(packedSources, packedTarget, map);
169-
return;
170-
}
163+
if (!haveSlowSource && target is PackedTuple packedTarget) {
164+
Copy3TuplesWithMappingFast(packedSources, packedTarget, map);
165+
return;
171166
}
172167

173168
Copy3TuplesWithMappingSlow(sources, target, map);
@@ -185,7 +180,7 @@ public static void CopyTo(this FixedList3<Tuple> sources, Tuple target, Pair<int
185180
/// <returns></returns>
186181
public static Tuple Combine(this Tuple left, Tuple right)
187182
{
188-
var transform = new CombineTransform(false, new[] {left.Descriptor, right.Descriptor});
183+
var transform = new CombineTransform(false, new[] { left.Descriptor, right.Descriptor });
189184
return transform.Apply(TupleTransformType.TransformedTuple, left, right);
190185
}
191186

@@ -229,30 +224,30 @@ public static Tuple GetSegment(this Tuple tuple, in Segment<int> segment)
229224
/// <exception cref="ArgumentException">Tuple descriptors mismatch.</exception>
230225
public static void MergeWith(this Tuple origin, Tuple difference, int startIndex, int length, MergeBehavior behavior)
231226
{
232-
if (difference==null)
227+
if (difference == null)
233228
return;
234-
if (origin.Descriptor!=difference.Descriptor)
229+
if (origin.Descriptor != difference.Descriptor)
235230
throw new ArgumentException(string.Format(Strings.ExInvalidTupleDescriptorExpectedDescriptorIs, origin.Descriptor), "difference");
236231

237232
var packedOrigin = origin as PackedTuple;
238233
var packedDifference = difference as PackedTuple;
239-
var useFast = packedOrigin!=null && packedDifference!=null;
234+
var useFast = packedOrigin != null && packedDifference != null;
240235

241236
switch (behavior) {
242-
case MergeBehavior.PreferOrigin:
243-
if (useFast)
244-
MergeTuplesPreferOriginFast(packedOrigin, packedDifference, startIndex, length);
245-
else
246-
MergeTuplesPreferOriginSlow(origin, difference, startIndex, length);
247-
break;
248-
case MergeBehavior.PreferDifference:
249-
if (useFast)
250-
PartiallyCopyTupleFast(packedDifference, packedOrigin, startIndex, startIndex, length);
251-
else
252-
PartiallyCopyTupleSlow(difference, origin, startIndex, startIndex, length);
253-
break;
254-
default:
255-
throw new ArgumentOutOfRangeException("behavior");
237+
case MergeBehavior.PreferOrigin:
238+
if (useFast)
239+
MergeTuplesPreferOriginFast(packedOrigin, packedDifference, startIndex, length);
240+
else
241+
MergeTuplesPreferOriginSlow(origin, difference, startIndex, length);
242+
break;
243+
case MergeBehavior.PreferDifference:
244+
if (useFast)
245+
PartiallyCopyTupleFast(packedDifference, packedOrigin, startIndex, startIndex, length);
246+
else
247+
PartiallyCopyTupleSlow(difference, origin, startIndex, startIndex, length);
248+
break;
249+
default:
250+
throw new ArgumentOutOfRangeException("behavior");
256251
}
257252
}
258253

@@ -338,7 +333,7 @@ public static void MergeWith(this Tuple origin, Tuple difference)
338333
/// as the specified <paramref name="source"/> tuple.</returns>
339334
public static RegularTuple ToRegular(this Tuple source)
340335
{
341-
if (source==null)
336+
if (source == null)
342337
return null;
343338
var result = Tuple.Create(source.Descriptor);
344339
source.CopyTo(result);
@@ -353,7 +348,7 @@ public static RegularTuple ToRegular(this Tuple source)
353348
/// <returns>Read-only version of <paramref name="source"/> tuple.</returns>
354349
public static Tuple ToReadOnly(this Tuple source, TupleTransformType transformType)
355350
{
356-
if (source==null)
351+
if (source == null)
357352
return null;
358353
return ReadOnlyTransform.Instance.Apply(transformType, source);
359354
}
@@ -365,7 +360,7 @@ public static Tuple ToReadOnly(this Tuple source, TupleTransformType transformTy
365360
/// <returns>Fast read-only version of <paramref name="source"/> tuple.</returns>
366361
public static Tuple ToFastReadOnly(this Tuple source)
367362
{
368-
if (source==null) {
363+
if (source == null) {
369364
return null;
370365
}
371366

@@ -386,14 +381,16 @@ public static BitArray GetFieldStateMap(this Tuple target, TupleFieldState reque
386381
var result = new BitArray(count);
387382

388383
switch (requestedState) {
389-
case TupleFieldState.Default:
390-
for (int i = 0; i < count; i++)
391-
result[i] = target.GetFieldState(i)==0;
392-
break;
393-
default:
394-
for (int i = 0; i < count; i++)
395-
result[i] = (requestedState & target.GetFieldState(i)) != 0;
396-
break;
384+
case TupleFieldState.Default:
385+
for (int i = 0; i < count; i++) {
386+
result[i] = target.GetFieldState(i) == 0;
387+
}
388+
break;
389+
default:
390+
for (int i = 0; i < count; i++) {
391+
result[i] = (requestedState & target.GetFieldState(i)) != 0;
392+
}
393+
break;
397394
}
398395
return result;
399396
}
@@ -407,7 +404,7 @@ public static BitArray GetFieldStateMap(this Tuple target, TupleFieldState reque
407404
public static void Initialize(this Tuple target, BitArray nullableMap)
408405
{
409406
var descriptor = target.Descriptor;
410-
if (descriptor.Count!=nullableMap.Count)
407+
if (descriptor.Count != nullableMap.Count)
411408
throw new ArgumentException(String.Format(Strings.ExInvalidFieldMapSizeExpectedX, descriptor.Count));
412409

413410
for (int i = 0; i < target.Count; i++) {
@@ -434,8 +431,8 @@ private static void CopyValue(Tuple source, int sourceIndex, Tuple target, int t
434431

435432
private static void CopyPackedValue(PackedTuple source, int sourceIndex, PackedTuple target, int targetIndex)
436433
{
437-
ref var sourceDescriptor = ref source.PackedDescriptor.FieldDescriptors[sourceIndex];
438-
ref var targetDescriptor = ref target.PackedDescriptor.FieldDescriptors[targetIndex];
434+
ref readonly var sourceDescriptor = ref source.PackedDescriptor.FieldDescriptors[sourceIndex];
435+
ref readonly var targetDescriptor = ref target.PackedDescriptor.FieldDescriptors[targetIndex];
439436

440437
var fieldState = source.GetFieldState(sourceDescriptor);
441438
if (!fieldState.IsAvailable()) {

0 commit comments

Comments
 (0)